gitignore cleanup and benchmark tests added
Costa Tsaousis (ktsaou) committed
Feb 19, 2018 at 21:35 UTC
4c5afdd516692c55fea048e38e58a634532a1e04
5 files changed
+1698
-40
.gitignore
+39
-39
@@ -5,6 +5,9 @@
5
config.h.in
6
Makefile.in
7
*~
8
+*.old
9
+*.log
10
+*.pyc
11
12
Makefile
13
aclocal.m4
@@ -12,7 +15,6 @@ autom4te.cache
15
compile
16
config.guess
17
config.h
15
-config.log
18
config.status
19
config.sub
20
configure
@@ -22,45 +24,37 @@ libtool
24
ltmain.sh
25
missing
26
stamp-h1
27
+netdata.spec
28
29
+# netdata binaries
30
netdata
31
apps.plugin
32
freeipmi.plugin
29
-netdata.spec
33
+cgroup-network
34
35
+# netdata makeself archives
36
*.tar.*
37
+*.run
38
33
-cmake-build-debug/
39
+# netdata makeself downloads
40
makeself/tmp/
35
-sitespeed-result/
41
+
42
+# coverity
43
cov-int/
44
netdata-coverity-analysis.tgz
45
.coverity-token
46
.coverity-build
47
41
-.cproject
48
+.cproject/
49
.idea/
50
.vscode/
44
-.project
51
+.project/
52
+.settings/
53
README
54
TODO.md
47
-asan_symbolize.py
48
-charts.d/bind.chart.sh
55
conf.d/netdata.conf
50
-conf.d/netdata.conf.old
51
-isolate-0x1e0e170-v8.log
52
-lan-hosts.sh
53
-modp_numtoa.c
54
-plugins.d/apache_mod_status.plugin
55
-plugins.d/apps.plugin.old
56
-src/.cproject
57
-src/.project
58
-src/.settings/
56
src/TODO.txt
60
-src/rrddim_file.c
61
-system/netdata.service
62
-valgrind.log
63
-valgrind2.log
57
+
58
web/chart-info/
59
web/control.html
60
web/datasource.css
@@ -76,43 +70,49 @@ system/netdata-lsb
70
system/netdata-openrc
71
system/netdata-init-d
72
system/netdata.logrotate
79
-python.d/python-modules-installer.sh
73
+system/netdata.service
74
+system/netdata-freebsd
75
81
-netdata-installer.log
76
+# installer generated files
77
netdata-uninstaller.sh
78
netdata-updater.sh
79
85
-gmon.out
86
-gmon.txt
87
-apps.plugin-profiler.sh
88
-
80
+# cmake files
81
+cmake-build-debug/
82
CMakeCache.txt
83
CMakeFiles/
84
cmake_install.cmake
85
86
+# jetbrains IDE
87
.jetbrains*
88
89
.DS_Store
90
91
contrib/debian/changelog
98
-profile/benchmark-dictionary
99
-profile/benchmark-registry
100
-profile/test-eval
101
-profile/benchmark-line-parsing
102
-profile/statsd-stress
103
-
104
-*.pyc
105
-*.run
92
93
+# converted diagrams
94
diagrams/*.png
95
diagrams/*.svg
96
diagrams/*.atxt
97
diagrams/plantuml.jar
98
112
-src/cgroup-network
113
-vgcore.*
114
-
99
+# cppcheck
100
src/cppcheck-build/
116
-makeself/debug/
101
102
+# debugging / profiling
103
+makeself/debug/
104
+profile/benchmark-dictionary
105
+profile/benchmark-registry
106
+profile/test-eval
107
+profile/benchmark-line-parsing
108
+profile/benchmark-procfile-parser
109
+profile/statsd-stress
110
+oprofile_data/
111
+vgcore.*
112
+callgrind.out.*
113
+gmon.out
114
+gmon.txt
115
+sitespeed-result/
116
117
+# tests and temp files
118
+python.d/python-modules-installer.sh
profile/Makefile
+7
-1
@@ -1,5 +1,11 @@
1
2
+COMMON_CFLAGS=-I ../src/ -I ../
3
+PROFILE_CFLAGS=-O1 -ggdb -Wall -Wextra
4
+
5
+benchmark-procfile-parser: benchmark-procfile-parser.c
6
+ gcc ${PROFILE_CFLAGS} ${COMMON_CFLAGS} -o $@ $^ ../src/log.o ../src/procfile.o ../src/threads.o ../src/locks.o ../src/common.o ../src/clocks.o ../src/web_buffer.o ../src/storage_number.o -pthread -lm
7
+
8
statsd-stress: statsd-stress.c
9
gcc -O2 -Wall -Wextra -o $@ $^ -pthread
10
5
-all: statsd-stress
11
+all: statsd-stress benchmark-procfile-parser
profile/benchmark-line-parsing.c
new
+662
@@ -0,0 +1,662 @@
1
+#include <stdio.h>
2
+#include <inttypes.h>
3
+#include <string.h>
4
+#include <stdlib.h>
5
+#include <ctype.h>
6
+#include <sys/time.h>
7
+
8
+#define likely(x) __builtin_expect(!!(x), 1)
9
+#define unlikely(x) __builtin_expect(!!(x), 0)
10
+
11
+#define simple_hash(name) ({ \
12
+ register unsigned char *__hash_source = (unsigned char *)(name); \
13
+ register uint32_t __hash_value = 0x811c9dc5; \
14
+ while (*__hash_source) { \
15
+ __hash_value *= 16777619; \
16
+ __hash_value ^= (uint32_t) *__hash_source++; \
17
+ } \
18
+ __hash_value; \
19
+})
20
+
21
+static inline uint32_t simple_hash2(const char *name) {
22
+ register unsigned char *s = (unsigned char *)name;
23
+ register uint32_t hval = 0x811c9dc5;
24
+ while (*s) {
25
+ hval *= 16777619;
26
+ hval ^= (uint32_t) *s++;
27
+ }
28
+ return hval;
29
+}
30
+
31
+static inline unsigned long long fast_strtoull(const char *s) {
32
+ register unsigned long long n = 0;
33
+ register char c;
34
+ for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) {
35
+ n *= 10;
36
+ n += c - '0';
37
+ // n = (n << 1) + (n << 3) + (c - '0');
38
+ }
39
+ return n;
40
+}
41
+
42
+static uint32_t cache_hash = 0;
43
+static uint32_t rss_hash = 0;
44
+static uint32_t rss_huge_hash = 0;
45
+static uint32_t mapped_file_hash = 0;
46
+static uint32_t writeback_hash = 0;
47
+static uint32_t dirty_hash = 0;
48
+static uint32_t swap_hash = 0;
49
+static uint32_t pgpgin_hash = 0;
50
+static uint32_t pgpgout_hash = 0;
51
+static uint32_t pgfault_hash = 0;
52
+static uint32_t pgmajfault_hash = 0;
53
+static uint32_t inactive_anon_hash = 0;
54
+static uint32_t active_anon_hash = 0;
55
+static uint32_t inactive_file_hash = 0;
56
+static uint32_t active_file_hash = 0;
57
+static uint32_t unevictable_hash = 0;
58
+static uint32_t hierarchical_memory_limit_hash = 0;
59
+static uint32_t total_cache_hash = 0;
60
+static uint32_t total_rss_hash = 0;
61
+static uint32_t total_rss_huge_hash = 0;
62
+static uint32_t total_mapped_file_hash = 0;
63
+static uint32_t total_writeback_hash = 0;
64
+static uint32_t total_dirty_hash = 0;
65
+static uint32_t total_swap_hash = 0;
66
+static uint32_t total_pgpgin_hash = 0;
67
+static uint32_t total_pgpgout_hash = 0;
68
+static uint32_t total_pgfault_hash = 0;
69
+static uint32_t total_pgmajfault_hash = 0;
70
+static uint32_t total_inactive_anon_hash = 0;
71
+static uint32_t total_active_anon_hash = 0;
72
+static uint32_t total_inactive_file_hash = 0;
73
+static uint32_t total_active_file_hash = 0;
74
+static uint32_t total_unevictable_hash = 0;
75
+
76
+char *strings[] = {
77
+ "cache",
78
+ "rss",
79
+ "rss_huge",
80
+ "mapped_file",
81
+ "writeback",
82
+ "dirty",
83
+ "swap",
84
+ "pgpgin",
85
+ "pgpgout",
86
+ "pgfault",
87
+ "pgmajfault",
88
+ "inactive_anon",
89
+ "active_anon",
90
+ "inactive_file",
91
+ "active_file",
92
+ "unevictable",
93
+ "hierarchical_memory_limit",
94
+ "total_cache",
95
+ "total_rss",
96
+ "total_rss_huge",
97
+ "total_mapped_file",
98
+ "total_writeback",
99
+ "total_dirty",
100
+ "total_swap",
101
+ "total_pgpgin",
102
+ "total_pgpgout",
103
+ "total_pgfault",
104
+ "total_pgmajfault",
105
+ "total_inactive_anon",
106
+ "total_active_anon",
107
+ "total_inactive_file",
108
+ "total_active_file",
109
+ "total_unevictable",
110
+ NULL
111
+};
112
+
113
+unsigned long long values1[12] = { 0 };
114
+unsigned long long values2[12] = { 0 };
115
+unsigned long long values3[12] = { 0 };
116
+unsigned long long values4[12] = { 0 };
117
+unsigned long long values5[12] = { 0 };
118
+unsigned long long values6[12] = { 0 };
119
+
120
+#define NUMBER1 "12345678901234"
121
+#define NUMBER2 "23456789012345"
122
+#define NUMBER3 "34567890123456"
123
+#define NUMBER4 "45678901234567"
124
+#define NUMBER5 "56789012345678"
125
+#define NUMBER6 "67890123456789"
126
+#define NUMBER7 "78901234567890"
127
+#define NUMBER8 "89012345678901"
128
+#define NUMBER9 "90123456789012"
129
+#define NUMBER10 "12345678901234"
130
+#define NUMBER11 "23456789012345"
131
+
132
+// simple system strcmp()
133
+void test1() {
134
+ int i;
135
+ for(i = 0; strings[i] ; i++) {
136
+ char *s = strings[i];
137
+
138
+ if(unlikely(!strcmp(s, "cache")))
139
+ values1[i] = strtoull(NUMBER1, NULL, 10);
140
+
141
+ else if(unlikely(!strcmp(s, "rss")))
142
+ values1[i] = strtoull(NUMBER2, NULL, 10);
143
+
144
+ else if(unlikely(!strcmp(s, "rss_huge")))
145
+ values1[i] = strtoull(NUMBER3, NULL, 10);
146
+
147
+ else if(unlikely(!strcmp(s, "mapped_file")))
148
+ values1[i] = strtoull(NUMBER4, NULL, 10);
149
+
150
+ else if(unlikely(!strcmp(s, "writeback")))
151
+ values1[i] = strtoull(NUMBER5, NULL, 10);
152
+
153
+ else if(unlikely(!strcmp(s, "dirty")))
154
+ values1[i] = strtoull(NUMBER6, NULL, 10);
155
+
156
+ else if(unlikely(!strcmp(s, "swap")))
157
+ values1[i] = strtoull(NUMBER7, NULL, 10);
158
+
159
+ else if(unlikely(!strcmp(s, "pgpgin")))
160
+ values1[i] = strtoull(NUMBER8, NULL, 10);
161
+
162
+ else if(unlikely(!strcmp(s, "pgpgout")))
163
+ values1[i] = strtoull(NUMBER9, NULL, 10);
164
+
165
+ else if(unlikely(!strcmp(s, "pgfault")))
166
+ values1[i] = strtoull(NUMBER10, NULL, 10);
167
+
168
+ else if(unlikely(!strcmp(s, "pgmajfault")))
169
+ values1[i] = strtoull(NUMBER11, NULL, 10);
170
+ }
171
+}
172
+
173
+// inline simple_hash() with system strtoull()
174
+void test2() {
175
+ int i;
176
+ for(i = 0; strings[i] ; i++) {
177
+ char *s = strings[i];
178
+ uint32_t hash = simple_hash2(s);
179
+
180
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache")))
181
+ values2[i] = strtoull(NUMBER1, NULL, 10);
182
+
183
+ else if(unlikely(hash == rss_hash && !strcmp(s, "rss")))
184
+ values2[i] = strtoull(NUMBER2, NULL, 10);
185
+
186
+ else if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge")))
187
+ values2[i] = strtoull(NUMBER3, NULL, 10);
188
+
189
+ else if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file")))
190
+ values2[i] = strtoull(NUMBER4, NULL, 10);
191
+
192
+ else if(unlikely(hash == writeback_hash && !strcmp(s, "writeback")))
193
+ values2[i] = strtoull(NUMBER5, NULL, 10);
194
+
195
+ else if(unlikely(hash == dirty_hash && !strcmp(s, "dirty")))
196
+ values2[i] = strtoull(NUMBER6, NULL, 10);
197
+
198
+ else if(unlikely(hash == swap_hash && !strcmp(s, "swap")))
199
+ values2[i] = strtoull(NUMBER7, NULL, 10);
200
+
201
+ else if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin")))
202
+ values2[i] = strtoull(NUMBER8, NULL, 10);
203
+
204
+ else if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout")))
205
+ values2[i] = strtoull(NUMBER9, NULL, 10);
206
+
207
+ else if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault")))
208
+ values2[i] = strtoull(NUMBER10, NULL, 10);
209
+
210
+ else if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault")))
211
+ values2[i] = strtoull(NUMBER11, NULL, 10);
212
+ }
213
+}
214
+
215
+// statement expression simple_hash(), system strtoull()
216
+void test3() {
217
+ int i;
218
+ for(i = 0; strings[i] ; i++) {
219
+ char *s = strings[i];
220
+ uint32_t hash = simple_hash(s);
221
+
222
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache")))
223
+ values3[i] = strtoull(NUMBER1, NULL, 10);
224
+
225
+ else if(unlikely(hash == rss_hash && !strcmp(s, "rss")))
226
+ values3[i] = strtoull(NUMBER2, NULL, 10);
227
+
228
+ else if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge")))
229
+ values3[i] = strtoull(NUMBER3, NULL, 10);
230
+
231
+ else if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file")))
232
+ values3[i] = strtoull(NUMBER4, NULL, 10);
233
+
234
+ else if(unlikely(hash == writeback_hash && !strcmp(s, "writeback")))
235
+ values3[i] = strtoull(NUMBER5, NULL, 10);
236
+
237
+ else if(unlikely(hash == dirty_hash && !strcmp(s, "dirty")))
238
+ values3[i] = strtoull(NUMBER6, NULL, 10);
239
+
240
+ else if(unlikely(hash == swap_hash && !strcmp(s, "swap")))
241
+ values3[i] = strtoull(NUMBER7, NULL, 10);
242
+
243
+ else if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin")))
244
+ values3[i] = strtoull(NUMBER8, NULL, 10);
245
+
246
+ else if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout")))
247
+ values3[i] = strtoull(NUMBER9, NULL, 10);
248
+
249
+ else if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault")))
250
+ values3[i] = strtoull(NUMBER10, NULL, 10);
251
+
252
+ else if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault")))
253
+ values3[i] = strtoull(NUMBER11, NULL, 10);
254
+ }
255
+}
256
+
257
+
258
+// inline simple_hash(), if-continue checks
259
+void test4() {
260
+ int i;
261
+ for(i = 0; strings[i] ; i++) {
262
+ char *s = strings[i];
263
+ uint32_t hash = simple_hash2(s);
264
+
265
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache"))) {
266
+ values4[i] = strtoull(NUMBER1, NULL, 0);
267
+ continue;
268
+ }
269
+
270
+ if(unlikely(hash == rss_hash && !strcmp(s, "rss"))) {
271
+ values4[i] = strtoull(NUMBER2, NULL, 0);
272
+ continue;
273
+ }
274
+
275
+ if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge"))) {
276
+ values4[i] = strtoull(NUMBER3, NULL, 0);
277
+ continue;
278
+ }
279
+
280
+ if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file"))) {
281
+ values4[i] = strtoull(NUMBER4, NULL, 0);
282
+ continue;
283
+ }
284
+
285
+ if(unlikely(hash == writeback_hash && !strcmp(s, "writeback"))) {
286
+ values4[i] = strtoull(NUMBER5, NULL, 0);
287
+ continue;
288
+ }
289
+
290
+ if(unlikely(hash == dirty_hash && !strcmp(s, "dirty"))) {
291
+ values4[i] = strtoull(NUMBER6, NULL, 0);
292
+ continue;
293
+ }
294
+
295
+ if(unlikely(hash == swap_hash && !strcmp(s, "swap"))) {
296
+ values4[i] = strtoull(NUMBER7, NULL, 0);
297
+ continue;
298
+ }
299
+
300
+ if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin"))) {
301
+ values4[i] = strtoull(NUMBER8, NULL, 0);
302
+ continue;
303
+ }
304
+
305
+ if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout"))) {
306
+ values4[i] = strtoull(NUMBER9, NULL, 0);
307
+ continue;
308
+ }
309
+
310
+ if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault"))) {
311
+ values4[i] = strtoull(NUMBER10, NULL, 0);
312
+ continue;
313
+ }
314
+
315
+ if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))) {
316
+ values4[i] = strtoull(NUMBER11, NULL, 0);
317
+ continue;
318
+ }
319
+ }
320
+}
321
+
322
+// inline simple_hash(), if-else-if-else-if (netdata default)
323
+void test5() {
324
+ int i;
325
+ for(i = 0; strings[i] ; i++) {
326
+ char *s = strings[i];
327
+ uint32_t hash = simple_hash2(s);
328
+
329
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache")))
330
+ values5[i] = fast_strtoull(NUMBER1);
331
+
332
+ else if(unlikely(hash == rss_hash && !strcmp(s, "rss")))
333
+ values5[i] = fast_strtoull(NUMBER2);
334
+
335
+ else if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge")))
336
+ values5[i] = fast_strtoull(NUMBER3);
337
+
338
+ else if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file")))
339
+ values5[i] = fast_strtoull(NUMBER4);
340
+
341
+ else if(unlikely(hash == writeback_hash && !strcmp(s, "writeback")))
342
+ values5[i] = fast_strtoull(NUMBER5);
343
+
344
+ else if(unlikely(hash == dirty_hash && !strcmp(s, "dirty")))
345
+ values5[i] = fast_strtoull(NUMBER6);
346
+
347
+ else if(unlikely(hash == swap_hash && !strcmp(s, "swap")))
348
+ values5[i] = fast_strtoull(NUMBER7);
349
+
350
+ else if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin")))
351
+ values5[i] = fast_strtoull(NUMBER8);
352
+
353
+ else if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout")))
354
+ values5[i] = fast_strtoull(NUMBER9);
355
+
356
+ else if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault")))
357
+ values5[i] = fast_strtoull(NUMBER10);
358
+
359
+ else if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault")))
360
+ values5[i] = fast_strtoull(NUMBER11);
361
+ }
362
+}
363
+
364
+// ----------------------------------------------------------------------------
365
+
366
+struct entry {
367
+ char *name;
368
+ uint32_t hash;
369
+ int found;
370
+ void (*func)(void *data1, void *data2);
371
+ void *data1;
372
+ void *data2;
373
+ struct entry *prev, *next;
374
+};
375
+
376
+struct base {
377
+ int iteration;
378
+ int registered;
379
+ int wanted;
380
+ int found;
381
+ struct entry *entries, *last;
382
+};
383
+
384
+static inline void callback(void *data1, void *data2) {
385
+ char *string = data1;
386
+ unsigned long long *value = data2;
387
+ *value = fast_strtoull(string);
388
+}
389
+
390
+
391
+static inline struct base *entry(struct base *base, const char *name, void *data1, void *data2, void (*func)(void *, void *)) {
392
+ if(!base)
393
+ base = calloc(1, sizeof(struct base));
394
+
395
+ struct entry *e = malloc(sizeof(struct entry));
396
+ e->name = strdup(name);
397
+ e->hash = simple_hash2(e->name);
398
+ e->data1 = data1;
399
+ e->data2 = data2;
400
+ e->func = func;
401
+ e->prev = NULL;
402
+ e->next = base->entries;
403
+
404
+ if(base->entries) base->entries->prev = e;
405
+ else base->last = e;
406
+
407
+ base->entries = e;
408
+ base->registered++;
409
+ base->wanted = base->registered;
410
+
411
+ return base;
412
+}
413
+
414
+static inline int check(struct base *base, const char *s) {
415
+ uint32_t hash = simple_hash2(s);
416
+
417
+ if(likely(hash == base->last->hash && !strcmp(s, base->last->name))) {
418
+ base->last->found = 1;
419
+ base->found++;
420
+ if(base->last->func) base->last->func(base->last->data1, base->last->data2);
421
+ base->last = base->last->next;
422
+
423
+ if(!base->last)
424
+ base->last = base->entries;
425
+
426
+ if(base->found == base->registered)
427
+ return 1;
428
+
429
+ return 0;
430
+ }
431
+
432
+ // find it
433
+ struct entry *e;
434
+ for(e = base->entries; e ; e = e->next)
435
+ if(e->hash == hash && !strcmp(e->name, s))
436
+ break;
437
+
438
+ if(e == base->last) {
439
+ printf("ERROR\n");
440
+ exit(1);
441
+ }
442
+
443
+ if(e) {
444
+ // found
445
+
446
+ // run it
447
+ if(e->func) e->func(e->data1, e->data2);
448
+
449
+ // unlink it
450
+ if(e->next) e->next->prev = e->prev;
451
+ if(e->prev) e->prev->next = e->next;
452
+
453
+ if(base->entries == e)
454
+ base->entries = e->next;
455
+ }
456
+ else {
457
+ // not found
458
+
459
+ // create it
460
+ e = calloc(1, sizeof(struct entry));
461
+ e->name = strdup(s);
462
+ e->hash = hash;
463
+ }
464
+
465
+ // link it here
466
+ e->next = base->last;
467
+ if(base->last) {
468
+ e->prev = base->last->prev;
469
+ base->last->prev = e;
470
+
471
+ if(base->entries == base->last)
472
+ base->entries = e;
473
+ }
474
+ else
475
+ e->prev = NULL;
476
+
477
+ if(e->prev)
478
+ e->prev->next = e;
479
+
480
+ base->last = e->next;
481
+ if(!base->last)
482
+ base->last = base->entries;
483
+
484
+ e->found = 1;
485
+ base->found++;
486
+
487
+ if(base->found == base->registered)
488
+ return 1;
489
+
490
+ printf("relinked '%s' after '%s' and before '%s': ", e->name, e->prev?e->prev->name:"NONE", e->next?e->next->name:"NONE");
491
+ for(e = base->entries; e ; e = e->next) printf("%s ", e->name);
492
+ printf("\n");
493
+
494
+ return 0;
495
+}
496
+
497
+static inline void begin(struct base *base) {
498
+
499
+ if(unlikely(base->iteration % 60) == 1) {
500
+ base->wanted = 0;
501
+ struct entry *e;
502
+ for(e = base->entries; e ; e = e->next)
503
+ if(e->found) base->wanted++;
504
+ }
505
+
506
+ base->iteration++;
507
+ base->last = base->entries;
508
+ base->found = 0;
509
+}
510
+
511
+void test6() {
512
+
513
+ static struct base *base = NULL;
514
+
515
+ if(unlikely(!base)) {
516
+ base = entry(base, "cache", NUMBER1, &values6[0], callback);
517
+ base = entry(base, "rss", NUMBER2, &values6[1], callback);
518
+ base = entry(base, "rss_huge", NUMBER3, &values6[2], callback);
519
+ base = entry(base, "mapped_file", NUMBER4, &values6[3], callback);
520
+ base = entry(base, "writeback", NUMBER5, &values6[4], callback);
521
+ base = entry(base, "dirty", NUMBER6, &values6[5], callback);
522
+ base = entry(base, "swap", NUMBER7, &values6[6], callback);
523
+ base = entry(base, "pgpgin", NUMBER8, &values6[7], callback);
524
+ base = entry(base, "pgpgout", NUMBER9, &values6[8], callback);
525
+ base = entry(base, "pgfault", NUMBER10, &values6[9], callback);
526
+ base = entry(base, "pgmajfault", NUMBER11, &values6[10], callback);
527
+ }
528
+
529
+ begin(base);
530
+
531
+ int i;
532
+ for(i = 0; strings[i] ; i++) {
533
+ if(check(base, strings[i]))
534
+ break;
535
+ }
536
+}
537
+
538
+// ----------------------------------------------------------------------------
539
+
540
+
541
+// ==============
542
+// --- Poor man cycle counting.
543
+static unsigned long tsc;
544
+
545
+static void begin_tsc(void)
546
+{
547
+ unsigned long a, d;
548
+ asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx");
549
+ tsc = ((unsigned long)d << 32) | (unsigned long)a;
550
+}
551
+
552
+static unsigned long end_tsc(void)
553
+{
554
+ unsigned long a, d;
555
+ asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx");
556
+ return (((unsigned long)d << 32) | (unsigned long)a) - tsc;
557
+}
558
+// ===============
559
+
560
+static unsigned long long clk;
561
+
562
+static void begin_clock() {
563
+ struct timeval tv;
564
+ if(unlikely(gettimeofday(&tv, NULL) == -1))
565
+ return;
566
+ clk = tv.tv_sec * 1000000 + tv.tv_usec;
567
+}
568
+
569
+static unsigned long long end_clock() {
570
+ struct timeval tv;
571
+ if(unlikely(gettimeofday(&tv, NULL) == -1))
572
+ return -1;
573
+ return clk = tv.tv_sec * 1000000 + tv.tv_usec - clk;
574
+}
575
+
576
+void main(void)
577
+{
578
+ cache_hash = simple_hash("cache");
579
+ rss_hash = simple_hash("rss");
580
+ rss_huge_hash = simple_hash("rss_huge");
581
+ mapped_file_hash = simple_hash("mapped_file");
582
+ writeback_hash = simple_hash("writeback");
583
+ dirty_hash = simple_hash("dirty");
584
+ swap_hash = simple_hash("swap");
585
+ pgpgin_hash = simple_hash("pgpgin");
586
+ pgpgout_hash = simple_hash("pgpgout");
587
+ pgfault_hash = simple_hash("pgfault");
588
+ pgmajfault_hash = simple_hash("pgmajfault");
589
+ inactive_anon_hash = simple_hash("inactive_anon");
590
+ active_anon_hash = simple_hash("active_anon");
591
+ inactive_file_hash = simple_hash("inactive_file");
592
+ active_file_hash = simple_hash("active_file");
593
+ unevictable_hash = simple_hash("unevictable");
594
+ hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
595
+ total_cache_hash = simple_hash("total_cache");
596
+ total_rss_hash = simple_hash("total_rss");
597
+ total_rss_huge_hash = simple_hash("total_rss_huge");
598
+ total_mapped_file_hash = simple_hash("total_mapped_file");
599
+ total_writeback_hash = simple_hash("total_writeback");
600
+ total_dirty_hash = simple_hash("total_dirty");
601
+ total_swap_hash = simple_hash("total_swap");
602
+ total_pgpgin_hash = simple_hash("total_pgpgin");
603
+ total_pgpgout_hash = simple_hash("total_pgpgout");
604
+ total_pgfault_hash = simple_hash("total_pgfault");
605
+ total_pgmajfault_hash = simple_hash("total_pgmajfault");
606
+ total_inactive_anon_hash = simple_hash("total_inactive_anon");
607
+ total_active_anon_hash = simple_hash("total_active_anon");
608
+ total_inactive_file_hash = simple_hash("total_inactive_file");
609
+ total_active_file_hash = simple_hash("total_active_file");
610
+ total_unevictable_hash = simple_hash("total_unevictable");
611
+
612
+ // cache functions
613
+ (void)simple_hash2("hello world");
614
+ (void)strcmp("1", "2");
615
+ (void)strtoull("123", NULL, 0);
616
+
617
+ unsigned long i, c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;
618
+ unsigned long max = 200000;
619
+
620
+ begin_clock();
621
+ for(i = 0; i <= max ;i++) test1();
622
+ c1 = end_clock();
623
+
624
+ begin_clock();
625
+ for(i = 0; i <= max ;i++) test2();
626
+ c2 = end_clock();
627
+
628
+ begin_clock();
629
+ for(i = 0; i <= max ;i++) test3();
630
+ c3 = end_clock();
631
+
632
+ begin_clock();
633
+ for(i = 0; i <= max ;i++) test4();
634
+ c4 = end_clock();
635
+
636
+ begin_clock();
637
+ for(i = 0; i <= max ;i++) test5();
638
+ c5 = end_clock();
639
+
640
+ begin_clock();
641
+ for(i = 0; i <= max ;i++) test6();
642
+ c6 = end_clock();
643
+
644
+ for(i = 0; i < 11 ; i++)
645
+ printf("value %lu: %llu %llu %llu %llu %llu %llu\n", i, values1[i], values2[i], values3[i], values4[i], values5[i], values6[i]);
646
+
647
+ printf("\n\nRESULTS\n");
648
+ printf("test1() in %lu usecs: simple system strcmp().\n"
649
+ "test2() in %lu usecs: inline simple_hash() with system strtoull().\n"
650
+ "test3() in %lu usecs: statement expression simple_hash(), system strtoull().\n"
651
+ "test4() in %lu usecs: inline simple_hash(), if-continue checks.\n"
652
+ "test5() in %lu usecs: inline simple_hash(), if-else-if-else-if (netdata default).\n"
653
+ "test6() in %lu usecs: adaptive re-sortable array (wow!)\n"
654
+ , c1
655
+ , c2
656
+ , c3
657
+ , c4
658
+ , c5
659
+ , c6
660
+ );
661
+
662
+}
profile/benchmark-procfile-parser.c
new
+328
@@ -0,0 +1,328 @@
1
+#include "config.h"
2
+#include "common.h"
3
+#include "clocks.h"
4
+
5
+void netdata_cleanup_and_exit(int ret) {
6
+ exit(ret);
7
+}
8
+
9
+#define PF_PREFIX "PROCFILE"
10
+#define PFWORDS_INCREASE_STEP 200
11
+#define PFLINES_INCREASE_STEP 10
12
+#define PROCFILE_INCREMENT_BUFFER 512
13
+extern size_t procfile_max_lines;
14
+extern size_t procfile_max_words;
15
+extern size_t procfile_max_allocation;
16
+
17
+
18
+static inline void pflines_reset(pflines *fl) {
19
+ // debug(D_PROCFILE, PF_PREFIX ": reseting lines");
20
+
21
+ fl->len = 0;
22
+}
23
+
24
+static inline void pflines_free(pflines *fl) {
25
+ // debug(D_PROCFILE, PF_PREFIX ": freeing lines");
26
+
27
+ freez(fl);
28
+}
29
+
30
+static inline void pfwords_reset(pfwords *fw) {
31
+ // debug(D_PROCFILE, PF_PREFIX ": reseting words");
32
+ fw->len = 0;
33
+}
34
+
35
+
36
+static inline void pfwords_add(procfile *ff, char *str) {
37
+ // debug(D_PROCFILE, PF_PREFIX ": adding word No %d: '%s'", fw->len, str);
38
+
39
+ pfwords *fw = ff->words;
40
+ if(unlikely(fw->len == fw->size)) {
41
+ // debug(D_PROCFILE, PF_PREFIX ": expanding words");
42
+
43
+ ff->words = fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
44
+ fw->size += PFWORDS_INCREASE_STEP;
45
+ }
46
+
47
+ fw->words[fw->len++] = str;
48
+}
49
+
50
+NEVERNULL
51
+static inline size_t *pflines_add(procfile *ff) {
52
+ // debug(D_PROCFILE, PF_PREFIX ": adding line %d at word %d", fl->len, first_word);
53
+
54
+ pflines *fl = ff->lines;
55
+ if(unlikely(fl->len == fl->size)) {
56
+ // debug(D_PROCFILE, PF_PREFIX ": expanding lines");
57
+
58
+ ff->lines = fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
59
+ fl->size += PFLINES_INCREASE_STEP;
60
+ }
61
+
62
+ ffline *ffl = &fl->lines[fl->len++];
63
+ ffl->words = 0;
64
+ ffl->first = ff->words->len;
65
+
66
+ return &ffl->words;
67
+}
68
+
69
+
70
+NOINLINE
71
+static void procfile_parser(procfile *ff) {
72
+ // debug(D_PROCFILE, PF_PREFIX ": Parsing file '%s'", ff->filename);
73
+
74
+ char *s = ff->data // our current position
75
+ , *e = &ff->data[ff->len] // the terminating null
76
+ , *t = ff->data; // the first character of a word (or quoted / parenthesized string)
77
+
78
+ // the look up array to find our type of character
79
+ PF_CHAR_TYPE *separators = ff->separators;
80
+
81
+ char quote = 0; // the quote character - only when in quoted string
82
+ size_t opened = 0; // counts the number of open parenthesis
83
+
84
+ size_t *line_words = pflines_add(ff);
85
+
86
+ while(s < e) {
87
+ PF_CHAR_TYPE ct = separators[(unsigned char)(*s)];
88
+
89
+ // this is faster than a switch()
90
+ // read more here: http://lazarenko.me/switch/
91
+ switch(ct) {
92
+ case PF_CHAR_IS_SEPARATOR:
93
+ if(!quote && !opened) {
94
+ if (s != t) {
95
+ // separator, but we have word before it
96
+ *s = '\0';
97
+ pfwords_add(ff, t);
98
+ (*line_words)++;
99
+ }
100
+ t = s + 1;
101
+ }
102
+ // fallthrough
103
+
104
+ case PF_CHAR_IS_WORD:
105
+ s++;
106
+ break;
107
+
108
+
109
+ case PF_CHAR_IS_NEWLINE:
110
+ // end of line
111
+
112
+ *s = '\0';
113
+ pfwords_add(ff, t);
114
+ (*line_words)++;
115
+ t = ++s;
116
+
117
+ // debug(D_PROCFILE, PF_PREFIX ": ended line %d with %d words", l, ff->lines->lines[l].words);
118
+
119
+ line_words = pflines_add(ff);
120
+ break;
121
+
122
+ case PF_CHAR_IS_QUOTE:
123
+ if(unlikely(!quote && s == t)) {
124
+ // quote opened at the beginning
125
+ quote = *s;
126
+ t = ++s;
127
+ }
128
+ else if(unlikely(quote && quote == *s)) {
129
+ // quote closed
130
+ quote = 0;
131
+
132
+ *s = '\0';
133
+ pfwords_add(ff, t);
134
+ (*line_words)++;
135
+ t = ++s;
136
+ }
137
+ else
138
+ s++;
139
+ break;
140
+
141
+ case PF_CHAR_IS_OPEN:
142
+ if(s == t) {
143
+ opened++;
144
+ t = ++s;
145
+ }
146
+ else if(opened) {
147
+ opened++;
148
+ s++;
149
+ }
150
+ else
151
+ s++;
152
+ break;
153
+
154
+ case PF_CHAR_IS_CLOSE:
155
+ if(opened) {
156
+ opened--;
157
+
158
+ if(!opened) {
159
+ *s = '\0';
160
+ pfwords_add(ff, t);
161
+ (*line_words)++;
162
+ t = ++s;
163
+ }
164
+ else
165
+ s++;
166
+ }
167
+ else
168
+ s++;
169
+ break;
170
+
171
+ default:
172
+ fatal("Internal Error: procfile_readall() does not handle all the cases.");
173
+ }
174
+ }
175
+
176
+ if(likely(s > t && t < e)) {
177
+ // the last word
178
+ if(unlikely(ff->len >= ff->size)) {
179
+ // we are going to loose the last byte
180
+ s = &ff->data[ff->size - 1];
181
+ }
182
+
183
+ *s = '\0';
184
+ pfwords_add(ff, t);
185
+ (*line_words)++;
186
+ // t = ++s;
187
+ }
188
+}
189
+
190
+
191
+procfile *procfile_readall1(procfile *ff) {
192
+ // debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
193
+
194
+ ff->len = 0; // zero the used size
195
+ ssize_t r = 1; // read at least once
196
+ while(r > 0) {
197
+ ssize_t s = ff->len;
198
+ ssize_t x = ff->size - s;
199
+
200
+ if(unlikely(!x)) {
201
+ debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", procfile_filename(ff));
202
+ ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
203
+ ff->size += PROCFILE_INCREMENT_BUFFER;
204
+ }
205
+
206
+ debug(D_PROCFILE, "Reading file '%s', from position %zd with length %zd", procfile_filename(ff), s, (ssize_t)(ff->size - s));
207
+ r = read(ff->fd, &ff->data[s], ff->size - s);
208
+ if(unlikely(r == -1)) {
209
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s' on fd %d", procfile_filename(ff), ff->fd);
210
+ procfile_close(ff);
211
+ return NULL;
212
+ }
213
+
214
+ ff->len += r;
215
+ }
216
+
217
+ // debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
218
+ if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
219
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
220
+ procfile_close(ff);
221
+ return NULL;
222
+ }
223
+
224
+ pflines_reset(ff->lines);
225
+ pfwords_reset(ff->words);
226
+ procfile_parser(ff);
227
+
228
+ if(unlikely(procfile_adaptive_initial_allocation)) {
229
+ if(unlikely(ff->len > procfile_max_allocation)) procfile_max_allocation = ff->len;
230
+ if(unlikely(ff->lines->len > procfile_max_lines)) procfile_max_lines = ff->lines->len;
231
+ if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
232
+ }
233
+
234
+ // debug(D_PROCFILE, "File '%s' updated.", ff->filename);
235
+ return ff;
236
+}
237
+
238
+
239
+
240
+
241
+
242
+
243
+
244
+
245
+// ==============
246
+// --- Poor man cycle counting.
247
+static unsigned long tsc;
248
+
249
+void begin_tsc(void)
250
+{
251
+ unsigned long a, d;
252
+ asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx");
253
+ tsc = ((unsigned long)d << 32) | (unsigned long)a;
254
+}
255
+
256
+unsigned long end_tsc(void)
257
+{
258
+ unsigned long a, d;
259
+ asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx");
260
+ return (((unsigned long)d << 32) | (unsigned long)a) - tsc;
261
+}
262
+// ==============
263
+
264
+
265
+unsigned long test_netdata_internal(void) {
266
+ static procfile *ff = NULL;
267
+
268
+ ff = procfile_reopen(ff, "/proc/self/status", " \t:,-()/", PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
269
+ if(!ff) {
270
+ fprintf(stderr, "Failed to open filename\n");
271
+ exit(1);
272
+ }
273
+
274
+ begin_tsc();
275
+ ff = procfile_readall(ff);
276
+ unsigned long c = end_tsc();
277
+
278
+ if(!ff) {
279
+ fprintf(stderr, "Failed to read filename\n");
280
+ exit(1);
281
+ }
282
+
283
+ return c;
284
+}
285
+
286
+unsigned long test_method1(void) {
287
+ static procfile *ff = NULL;
288
+
289
+ ff = procfile_reopen(ff, "/proc/self/status", " \t:,-()/", PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
290
+ if(!ff) {
291
+ fprintf(stderr, "Failed to open filename\n");
292
+ exit(1);
293
+ }
294
+
295
+ begin_tsc();
296
+ ff = procfile_readall1(ff);
297
+ unsigned long c = end_tsc();
298
+
299
+ if(!ff) {
300
+ fprintf(stderr, "Failed to read filename\n");
301
+ exit(1);
302
+ }
303
+
304
+ return c;
305
+}
306
+
307
+//--- Test
308
+int main(int argc, char **argv)
309
+{
310
+ (void)argc; (void)argv;
311
+
312
+ int i, max = 1000000;
313
+
314
+ unsigned long c1 = 0;
315
+ test_netdata_internal();
316
+ for(i = 0; i < max ; i++)
317
+ c1 += test_netdata_internal();
318
+
319
+ unsigned long c2 = 0;
320
+ test_method1();
321
+ for(i = 0; i < max ; i++)
322
+ c2 += test_method1();
323
+
324
+ printf("netdata internal: completed in %lu cycles, %lu cycles per read, %0.2f %%.\n", c1, c1 / max, (float)c1 * 100.0 / (float)c1);
325
+ printf("method1 : completed in %lu cycles, %lu cycles per read, %0.2f %%.\n", c2, c2 / max, (float)c2 * 100.0 / (float)c1);
326
+
327
+ return 0;
328
+}
profile/benchmark-strcmp.c
new
+662
@@ -0,0 +1,662 @@
1
+#include <stdio.h>
2
+#include <inttypes.h>
3
+#include <string.h>
4
+#include <stdlib.h>
5
+#include <ctype.h>
6
+#include <sys/time.h>
7
+
8
+#define likely(x) __builtin_expect(!!(x), 1)
9
+#define unlikely(x) __builtin_expect(!!(x), 0)
10
+
11
+#define simple_hash(name) ({ \
12
+ register unsigned char *__hash_source = (unsigned char *)(name); \
13
+ register uint32_t __hash_value = 0x811c9dc5; \
14
+ while (*__hash_source) { \
15
+ __hash_value *= 16777619; \
16
+ __hash_value ^= (uint32_t) *__hash_source++; \
17
+ } \
18
+ __hash_value; \
19
+})
20
+
21
+static inline uint32_t simple_hash2(const char *name) {
22
+ register unsigned char *s = (unsigned char *)name;
23
+ register uint32_t hval = 0x811c9dc5;
24
+ while (*s) {
25
+ hval *= 16777619;
26
+ hval ^= (uint32_t) *s++;
27
+ }
28
+ return hval;
29
+}
30
+
31
+static inline unsigned long long fast_strtoull(const char *s) {
32
+ register unsigned long long n = 0;
33
+ register char c;
34
+ for(c = *s; c >= '0' && c <= '9' ; c = *(++s)) {
35
+ n *= 10;
36
+ n += c - '0';
37
+ // n = (n << 1) + (n << 3) + (c - '0');
38
+ }
39
+ return n;
40
+}
41
+
42
+static uint32_t cache_hash = 0;
43
+static uint32_t rss_hash = 0;
44
+static uint32_t rss_huge_hash = 0;
45
+static uint32_t mapped_file_hash = 0;
46
+static uint32_t writeback_hash = 0;
47
+static uint32_t dirty_hash = 0;
48
+static uint32_t swap_hash = 0;
49
+static uint32_t pgpgin_hash = 0;
50
+static uint32_t pgpgout_hash = 0;
51
+static uint32_t pgfault_hash = 0;
52
+static uint32_t pgmajfault_hash = 0;
53
+static uint32_t inactive_anon_hash = 0;
54
+static uint32_t active_anon_hash = 0;
55
+static uint32_t inactive_file_hash = 0;
56
+static uint32_t active_file_hash = 0;
57
+static uint32_t unevictable_hash = 0;
58
+static uint32_t hierarchical_memory_limit_hash = 0;
59
+static uint32_t total_cache_hash = 0;
60
+static uint32_t total_rss_hash = 0;
61
+static uint32_t total_rss_huge_hash = 0;
62
+static uint32_t total_mapped_file_hash = 0;
63
+static uint32_t total_writeback_hash = 0;
64
+static uint32_t total_dirty_hash = 0;
65
+static uint32_t total_swap_hash = 0;
66
+static uint32_t total_pgpgin_hash = 0;
67
+static uint32_t total_pgpgout_hash = 0;
68
+static uint32_t total_pgfault_hash = 0;
69
+static uint32_t total_pgmajfault_hash = 0;
70
+static uint32_t total_inactive_anon_hash = 0;
71
+static uint32_t total_active_anon_hash = 0;
72
+static uint32_t total_inactive_file_hash = 0;
73
+static uint32_t total_active_file_hash = 0;
74
+static uint32_t total_unevictable_hash = 0;
75
+
76
+char *strings[] = {
77
+ "cache",
78
+ "rss",
79
+ "rss_huge",
80
+ "mapped_file",
81
+ "writeback",
82
+ "dirty",
83
+ "swap",
84
+ "pgpgin",
85
+ "pgpgout",
86
+ "pgfault",
87
+ "pgmajfault",
88
+ "inactive_anon",
89
+ "active_anon",
90
+ "inactive_file",
91
+ "active_file",
92
+ "unevictable",
93
+ "hierarchical_memory_limit",
94
+ "total_cache",
95
+ "total_rss",
96
+ "total_rss_huge",
97
+ "total_mapped_file",
98
+ "total_writeback",
99
+ "total_dirty",
100
+ "total_swap",
101
+ "total_pgpgin",
102
+ "total_pgpgout",
103
+ "total_pgfault",
104
+ "total_pgmajfault",
105
+ "total_inactive_anon",
106
+ "total_active_anon",
107
+ "total_inactive_file",
108
+ "total_active_file",
109
+ "total_unevictable",
110
+ NULL
111
+};
112
+
113
+unsigned long long values1[12] = { 0 };
114
+unsigned long long values2[12] = { 0 };
115
+unsigned long long values3[12] = { 0 };
116
+unsigned long long values4[12] = { 0 };
117
+unsigned long long values5[12] = { 0 };
118
+unsigned long long values6[12] = { 0 };
119
+
120
+#define NUMBER1 "12345678901234"
121
+#define NUMBER2 "23456789012345"
122
+#define NUMBER3 "34567890123456"
123
+#define NUMBER4 "45678901234567"
124
+#define NUMBER5 "56789012345678"
125
+#define NUMBER6 "67890123456789"
126
+#define NUMBER7 "78901234567890"
127
+#define NUMBER8 "89012345678901"
128
+#define NUMBER9 "90123456789012"
129
+#define NUMBER10 "12345678901234"
130
+#define NUMBER11 "23456789012345"
131
+
132
+// simple system strcmp()
133
+void test1() {
134
+ int i;
135
+ for(i = 0; strings[i] ; i++) {
136
+ char *s = strings[i];
137
+
138
+ if(unlikely(!strcmp(s, "cache")))
139
+ values1[i] = strtoull(NUMBER1, NULL, 10);
140
+
141
+ else if(unlikely(!strcmp(s, "rss")))
142
+ values1[i] = strtoull(NUMBER2, NULL, 10);
143
+
144
+ else if(unlikely(!strcmp(s, "rss_huge")))
145
+ values1[i] = strtoull(NUMBER3, NULL, 10);
146
+
147
+ else if(unlikely(!strcmp(s, "mapped_file")))
148
+ values1[i] = strtoull(NUMBER4, NULL, 10);
149
+
150
+ else if(unlikely(!strcmp(s, "writeback")))
151
+ values1[i] = strtoull(NUMBER5, NULL, 10);
152
+
153
+ else if(unlikely(!strcmp(s, "dirty")))
154
+ values1[i] = strtoull(NUMBER6, NULL, 10);
155
+
156
+ else if(unlikely(!strcmp(s, "swap")))
157
+ values1[i] = strtoull(NUMBER7, NULL, 10);
158
+
159
+ else if(unlikely(!strcmp(s, "pgpgin")))
160
+ values1[i] = strtoull(NUMBER8, NULL, 10);
161
+
162
+ else if(unlikely(!strcmp(s, "pgpgout")))
163
+ values1[i] = strtoull(NUMBER9, NULL, 10);
164
+
165
+ else if(unlikely(!strcmp(s, "pgfault")))
166
+ values1[i] = strtoull(NUMBER10, NULL, 10);
167
+
168
+ else if(unlikely(!strcmp(s, "pgmajfault")))
169
+ values1[i] = strtoull(NUMBER11, NULL, 10);
170
+ }
171
+}
172
+
173
+// inline simple_hash() with system strtoull()
174
+void test2() {
175
+ int i;
176
+ for(i = 0; strings[i] ; i++) {
177
+ char *s = strings[i];
178
+ uint32_t hash = simple_hash2(s);
179
+
180
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache")))
181
+ values2[i] = strtoull(NUMBER1, NULL, 10);
182
+
183
+ else if(unlikely(hash == rss_hash && !strcmp(s, "rss")))
184
+ values2[i] = strtoull(NUMBER2, NULL, 10);
185
+
186
+ else if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge")))
187
+ values2[i] = strtoull(NUMBER3, NULL, 10);
188
+
189
+ else if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file")))
190
+ values2[i] = strtoull(NUMBER4, NULL, 10);
191
+
192
+ else if(unlikely(hash == writeback_hash && !strcmp(s, "writeback")))
193
+ values2[i] = strtoull(NUMBER5, NULL, 10);
194
+
195
+ else if(unlikely(hash == dirty_hash && !strcmp(s, "dirty")))
196
+ values2[i] = strtoull(NUMBER6, NULL, 10);
197
+
198
+ else if(unlikely(hash == swap_hash && !strcmp(s, "swap")))
199
+ values2[i] = strtoull(NUMBER7, NULL, 10);
200
+
201
+ else if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin")))
202
+ values2[i] = strtoull(NUMBER8, NULL, 10);
203
+
204
+ else if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout")))
205
+ values2[i] = strtoull(NUMBER9, NULL, 10);
206
+
207
+ else if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault")))
208
+ values2[i] = strtoull(NUMBER10, NULL, 10);
209
+
210
+ else if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault")))
211
+ values2[i] = strtoull(NUMBER11, NULL, 10);
212
+ }
213
+}
214
+
215
+// statement expression simple_hash(), system strtoull()
216
+void test3() {
217
+ int i;
218
+ for(i = 0; strings[i] ; i++) {
219
+ char *s = strings[i];
220
+ uint32_t hash = simple_hash(s);
221
+
222
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache")))
223
+ values3[i] = strtoull(NUMBER1, NULL, 10);
224
+
225
+ else if(unlikely(hash == rss_hash && !strcmp(s, "rss")))
226
+ values3[i] = strtoull(NUMBER2, NULL, 10);
227
+
228
+ else if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge")))
229
+ values3[i] = strtoull(NUMBER3, NULL, 10);
230
+
231
+ else if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file")))
232
+ values3[i] = strtoull(NUMBER4, NULL, 10);
233
+
234
+ else if(unlikely(hash == writeback_hash && !strcmp(s, "writeback")))
235
+ values3[i] = strtoull(NUMBER5, NULL, 10);
236
+
237
+ else if(unlikely(hash == dirty_hash && !strcmp(s, "dirty")))
238
+ values3[i] = strtoull(NUMBER6, NULL, 10);
239
+
240
+ else if(unlikely(hash == swap_hash && !strcmp(s, "swap")))
241
+ values3[i] = strtoull(NUMBER7, NULL, 10);
242
+
243
+ else if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin")))
244
+ values3[i] = strtoull(NUMBER8, NULL, 10);
245
+
246
+ else if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout")))
247
+ values3[i] = strtoull(NUMBER9, NULL, 10);
248
+
249
+ else if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault")))
250
+ values3[i] = strtoull(NUMBER10, NULL, 10);
251
+
252
+ else if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault")))
253
+ values3[i] = strtoull(NUMBER11, NULL, 10);
254
+ }
255
+}
256
+
257
+
258
+// inline simple_hash(), if-continue checks
259
+void test4() {
260
+ int i;
261
+ for(i = 0; strings[i] ; i++) {
262
+ char *s = strings[i];
263
+ uint32_t hash = simple_hash2(s);
264
+
265
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache"))) {
266
+ values4[i] = strtoull(NUMBER1, NULL, 0);
267
+ continue;
268
+ }
269
+
270
+ if(unlikely(hash == rss_hash && !strcmp(s, "rss"))) {
271
+ values4[i] = strtoull(NUMBER2, NULL, 0);
272
+ continue;
273
+ }
274
+
275
+ if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge"))) {
276
+ values4[i] = strtoull(NUMBER3, NULL, 0);
277
+ continue;
278
+ }
279
+
280
+ if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file"))) {
281
+ values4[i] = strtoull(NUMBER4, NULL, 0);
282
+ continue;
283
+ }
284
+
285
+ if(unlikely(hash == writeback_hash && !strcmp(s, "writeback"))) {
286
+ values4[i] = strtoull(NUMBER5, NULL, 0);
287
+ continue;
288
+ }
289
+
290
+ if(unlikely(hash == dirty_hash && !strcmp(s, "dirty"))) {
291
+ values4[i] = strtoull(NUMBER6, NULL, 0);
292
+ continue;
293
+ }
294
+
295
+ if(unlikely(hash == swap_hash && !strcmp(s, "swap"))) {
296
+ values4[i] = strtoull(NUMBER7, NULL, 0);
297
+ continue;
298
+ }
299
+
300
+ if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin"))) {
301
+ values4[i] = strtoull(NUMBER8, NULL, 0);
302
+ continue;
303
+ }
304
+
305
+ if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout"))) {
306
+ values4[i] = strtoull(NUMBER9, NULL, 0);
307
+ continue;
308
+ }
309
+
310
+ if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault"))) {
311
+ values4[i] = strtoull(NUMBER10, NULL, 0);
312
+ continue;
313
+ }
314
+
315
+ if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))) {
316
+ values4[i] = strtoull(NUMBER11, NULL, 0);
317
+ continue;
318
+ }
319
+ }
320
+}
321
+
322
+// inline simple_hash(), if-else-if-else-if (netdata default)
323
+void test5() {
324
+ int i;
325
+ for(i = 0; strings[i] ; i++) {
326
+ char *s = strings[i];
327
+ uint32_t hash = simple_hash2(s);
328
+
329
+ if(unlikely(hash == cache_hash && !strcmp(s, "cache")))
330
+ values5[i] = fast_strtoull(NUMBER1);
331
+
332
+ else if(unlikely(hash == rss_hash && !strcmp(s, "rss")))
333
+ values5[i] = fast_strtoull(NUMBER2);
334
+
335
+ else if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge")))
336
+ values5[i] = fast_strtoull(NUMBER3);
337
+
338
+ else if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file")))
339
+ values5[i] = fast_strtoull(NUMBER4);
340
+
341
+ else if(unlikely(hash == writeback_hash && !strcmp(s, "writeback")))
342
+ values5[i] = fast_strtoull(NUMBER5);
343
+
344
+ else if(unlikely(hash == dirty_hash && !strcmp(s, "dirty")))
345
+ values5[i] = fast_strtoull(NUMBER6);
346
+
347
+ else if(unlikely(hash == swap_hash && !strcmp(s, "swap")))
348
+ values5[i] = fast_strtoull(NUMBER7);
349
+
350
+ else if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin")))
351
+ values5[i] = fast_strtoull(NUMBER8);
352
+
353
+ else if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout")))
354
+ values5[i] = fast_strtoull(NUMBER9);
355
+
356
+ else if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault")))
357
+ values5[i] = fast_strtoull(NUMBER10);
358
+
359
+ else if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault")))
360
+ values5[i] = fast_strtoull(NUMBER11);
361
+ }
362
+}
363
+
364
+// ----------------------------------------------------------------------------
365
+
366
+struct entry {
367
+ char *name;
368
+ uint32_t hash;
369
+ int found;
370
+ void (*func)(void *data1, void *data2);
371
+ void *data1;
372
+ void *data2;
373
+ struct entry *prev, *next;
374
+};
375
+
376
+struct base {
377
+ int iteration;
378
+ int registered;
379
+ int wanted;
380
+ int found;
381
+ struct entry *entries, *last;
382
+};
383
+
384
+static inline void callback(void *data1, void *data2) {
385
+ char *string = data1;
386
+ unsigned long long *value = data2;
387
+ *value = fast_strtoull(string);
388
+}
389
+
390
+
391
+static inline struct base *entry(struct base *base, const char *name, void *data1, void *data2, void (*func)(void *, void *)) {
392
+ if(!base)
393
+ base = calloc(1, sizeof(struct base));
394
+
395
+ struct entry *e = malloc(sizeof(struct entry));
396
+ e->name = strdup(name);
397
+ e->hash = simple_hash2(e->name);
398
+ e->data1 = data1;
399
+ e->data2 = data2;
400
+ e->func = func;
401
+ e->prev = NULL;
402
+ e->next = base->entries;
403
+
404
+ if(base->entries) base->entries->prev = e;
405
+ else base->last = e;
406
+
407
+ base->entries = e;
408
+ base->registered++;
409
+ base->wanted = base->registered;
410
+
411
+ return base;
412
+}
413
+
414
+static inline int check(struct base *base, const char *s) {
415
+ uint32_t hash = simple_hash2(s);
416
+
417
+ if(likely(hash == base->last->hash && !strcmp(s, base->last->name))) {
418
+ base->last->found = 1;
419
+ base->found++;
420
+ if(base->last->func) base->last->func(base->last->data1, base->last->data2);
421
+ base->last = base->last->next;
422
+
423
+ if(!base->last)
424
+ base->last = base->entries;
425
+
426
+ if(base->found == base->registered)
427
+ return 1;
428
+
429
+ return 0;
430
+ }
431
+
432
+ // find it
433
+ struct entry *e;
434
+ for(e = base->entries; e ; e = e->next)
435
+ if(e->hash == hash && !strcmp(e->name, s))
436
+ break;
437
+
438
+ if(e == base->last) {
439
+ printf("ERROR\n");
440
+ exit(1);
441
+ }
442
+
443
+ if(e) {
444
+ // found
445
+
446
+ // run it
447
+ if(e->func) e->func(e->data1, e->data2);
448
+
449
+ // unlink it
450
+ if(e->next) e->next->prev = e->prev;
451
+ if(e->prev) e->prev->next = e->next;
452
+
453
+ if(base->entries == e)
454
+ base->entries = e->next;
455
+ }
456
+ else {
457
+ // not found
458
+
459
+ // create it
460
+ e = calloc(1, sizeof(struct entry));
461
+ e->name = strdup(s);
462
+ e->hash = hash;
463
+ }
464
+
465
+ // link it here
466
+ e->next = base->last;
467
+ if(base->last) {
468
+ e->prev = base->last->prev;
469
+ base->last->prev = e;
470
+
471
+ if(base->entries == base->last)
472
+ base->entries = e;
473
+ }
474
+ else
475
+ e->prev = NULL;
476
+
477
+ if(e->prev)
478
+ e->prev->next = e;
479
+
480
+ base->last = e->next;
481
+ if(!base->last)
482
+ base->last = base->entries;
483
+
484
+ e->found = 1;
485
+ base->found++;
486
+
487
+ if(base->found == base->registered)
488
+ return 1;
489
+
490
+ printf("relinked '%s' after '%s' and before '%s': ", e->name, e->prev?e->prev->name:"NONE", e->next?e->next->name:"NONE");
491
+ for(e = base->entries; e ; e = e->next) printf("%s ", e->name);
492
+ printf("\n");
493
+
494
+ return 0;
495
+}
496
+
497
+static inline void begin(struct base *base) {
498
+
499
+ if(unlikely(base->iteration % 60) == 1) {
500
+ base->wanted = 0;
501
+ struct entry *e;
502
+ for(e = base->entries; e ; e = e->next)
503
+ if(e->found) base->wanted++;
504
+ }
505
+
506
+ base->iteration++;
507
+ base->last = base->entries;
508
+ base->found = 0;
509
+}
510
+
511
+void test6() {
512
+
513
+ static struct base *base = NULL;
514
+
515
+ if(unlikely(!base)) {
516
+ base = entry(base, "cache", NUMBER1, &values6[0], callback);
517
+ base = entry(base, "rss", NUMBER2, &values6[1], callback);
518
+ base = entry(base, "rss_huge", NUMBER3, &values6[2], callback);
519
+ base = entry(base, "mapped_file", NUMBER4, &values6[3], callback);
520
+ base = entry(base, "writeback", NUMBER5, &values6[4], callback);
521
+ base = entry(base, "dirty", NUMBER6, &values6[5], callback);
522
+ base = entry(base, "swap", NUMBER7, &values6[6], callback);
523
+ base = entry(base, "pgpgin", NUMBER8, &values6[7], callback);
524
+ base = entry(base, "pgpgout", NUMBER9, &values6[8], callback);
525
+ base = entry(base, "pgfault", NUMBER10, &values6[9], callback);
526
+ base = entry(base, "pgmajfault", NUMBER11, &values6[10], callback);
527
+ }
528
+
529
+ begin(base);
530
+
531
+ int i;
532
+ for(i = 0; strings[i] ; i++) {
533
+ if(check(base, strings[i]))
534
+ break;
535
+ }
536
+}
537
+
538
+// ----------------------------------------------------------------------------
539
+
540
+
541
+// ==============
542
+// --- Poor man cycle counting.
543
+static unsigned long tsc;
544
+
545
+static void begin_tsc(void)
546
+{
547
+ unsigned long a, d;
548
+ asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx");
549
+ tsc = ((unsigned long)d << 32) | (unsigned long)a;
550
+}
551
+
552
+static unsigned long end_tsc(void)
553
+{
554
+ unsigned long a, d;
555
+ asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx");
556
+ return (((unsigned long)d << 32) | (unsigned long)a) - tsc;
557
+}
558
+// ===============
559
+
560
+static unsigned long long clk;
561
+
562
+static void begin_clock() {
563
+ struct timeval tv;
564
+ if(unlikely(gettimeofday(&tv, NULL) == -1))
565
+ return;
566
+ clk = tv.tv_sec * 1000000 + tv.tv_usec;
567
+}
568
+
569
+static unsigned long long end_clock() {
570
+ struct timeval tv;
571
+ if(unlikely(gettimeofday(&tv, NULL) == -1))
572
+ return -1;
573
+ return clk = tv.tv_sec * 1000000 + tv.tv_usec - clk;
574
+}
575
+
576
+void main(void)
577
+{
578
+ cache_hash = simple_hash("cache");
579
+ rss_hash = simple_hash("rss");
580
+ rss_huge_hash = simple_hash("rss_huge");
581
+ mapped_file_hash = simple_hash("mapped_file");
582
+ writeback_hash = simple_hash("writeback");
583
+ dirty_hash = simple_hash("dirty");
584
+ swap_hash = simple_hash("swap");
585
+ pgpgin_hash = simple_hash("pgpgin");
586
+ pgpgout_hash = simple_hash("pgpgout");
587
+ pgfault_hash = simple_hash("pgfault");
588
+ pgmajfault_hash = simple_hash("pgmajfault");
589
+ inactive_anon_hash = simple_hash("inactive_anon");
590
+ active_anon_hash = simple_hash("active_anon");
591
+ inactive_file_hash = simple_hash("inactive_file");
592
+ active_file_hash = simple_hash("active_file");
593
+ unevictable_hash = simple_hash("unevictable");
594
+ hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
595
+ total_cache_hash = simple_hash("total_cache");
596
+ total_rss_hash = simple_hash("total_rss");
597
+ total_rss_huge_hash = simple_hash("total_rss_huge");
598
+ total_mapped_file_hash = simple_hash("total_mapped_file");
599
+ total_writeback_hash = simple_hash("total_writeback");
600
+ total_dirty_hash = simple_hash("total_dirty");
601
+ total_swap_hash = simple_hash("total_swap");
602
+ total_pgpgin_hash = simple_hash("total_pgpgin");
603
+ total_pgpgout_hash = simple_hash("total_pgpgout");
604
+ total_pgfault_hash = simple_hash("total_pgfault");
605
+ total_pgmajfault_hash = simple_hash("total_pgmajfault");
606
+ total_inactive_anon_hash = simple_hash("total_inactive_anon");
607
+ total_active_anon_hash = simple_hash("total_active_anon");
608
+ total_inactive_file_hash = simple_hash("total_inactive_file");
609
+ total_active_file_hash = simple_hash("total_active_file");
610
+ total_unevictable_hash = simple_hash("total_unevictable");
611
+
612
+ // cache functions
613
+ (void)simple_hash2("hello world");
614
+ (void)strcmp("1", "2");
615
+ (void)strtoull("123", NULL, 0);
616
+
617
+ unsigned long i, c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0, c6 = 0;
618
+ unsigned long max = 200000;
619
+
620
+ begin_clock();
621
+ for(i = 0; i <= max ;i++) test1();
622
+ c1 = end_clock();
623
+
624
+ begin_clock();
625
+ for(i = 0; i <= max ;i++) test2();
626
+ c2 = end_clock();
627
+
628
+ begin_clock();
629
+ for(i = 0; i <= max ;i++) test3();
630
+ c3 = end_clock();
631
+
632
+ begin_clock();
633
+ for(i = 0; i <= max ;i++) test4();
634
+ c4 = end_clock();
635
+
636
+ begin_clock();
637
+ for(i = 0; i <= max ;i++) test5();
638
+ c5 = end_clock();
639
+
640
+ begin_clock();
641
+ for(i = 0; i <= max ;i++) test6();
642
+ c6 = end_clock();
643
+
644
+ for(i = 0; i < 11 ; i++)
645
+ printf("value %lu: %llu %llu %llu %llu %llu %llu\n", i, values1[i], values2[i], values3[i], values4[i], values5[i], values6[i]);
646
+
647
+ printf("\n\nRESULTS\n");
648
+ printf("test1() in %lu usecs: simple system strcmp().\n"
649
+ "test2() in %lu usecs: inline simple_hash() with system strtoull().\n"
650
+ "test3() in %lu usecs: statement expression simple_hash(), system strtoull().\n"
651
+ "test4() in %lu usecs: inline simple_hash(), if-continue checks.\n"
652
+ "test5() in %lu usecs: inline simple_hash(), if-else-if-else-if (netdata default).\n"
653
+ "test6() in %lu usecs: adaptive re-sortable array (wow!)\n"
654
+ , c1
655
+ , c2
656
+ , c3
657
+ , c4
658
+ , c5
659
+ , c6
660
+ );
661
+
662
+}