optimized pluginsd parsing for speed
Costa Tsaousis (ktsaou) committed
Apr 7, 2015 at 00:09 UTC
a3c28f5dfb0685c3aa3821e2f0fbf80d049aba5c
4 files changed
+143
-80
src/common.c
-38
@@ -87,44 +87,6 @@ char *mystrsep(char **ptr, char *s)
87
return(p);
88
}
89
90
-// like strsep() but:
91
-// it trims spaces before and after each value
92
-// it accepts quoted values in single or double quotes
93
-char *qstrsep(char **ptr)
94
-{
95
- if(!*ptr || !**ptr) return NULL;
96
-
97
- char *s, *p = *ptr;
98
-
99
- // skip leading spaces
100
- while(isspace(*p)) p++;
101
-
102
- // if the first char is a quote, assume quoted
103
- if(*p == '"' || *p == '\'') {
104
- char q = *p;
105
- s = ++p;
106
- while(*p && *p != q) p++;
107
-
108
- if(*p == q) {
109
- *p = '\0';
110
- p++;
111
- }
112
-
113
- *ptr = p;
114
- return s;
115
- }
116
-
117
- s = p;
118
- while(*p && !isspace(*p)) p++;
119
- if(!*p) *ptr = NULL;
120
- else {
121
- *p = '\0';
122
- *ptr = ++p;
123
- }
124
-
125
- return s;
126
-}
127
-
90
char *trim(char *s)
91
{
92
// skip leading spaces
src/common.h
-1
@@ -9,7 +9,6 @@
9
extern uint32_t simple_hash(const char *name);
10
extern void strreverse(char* begin, char* end);
11
extern char *mystrsep(char **ptr, char *s);
12
-extern char *qstrsep(char **ptr);
12
extern char *trim(char *s);
13
14
extern void *mymmap(const char *filename, unsigned long size, int flags);
src/plugin_tc.c
+2
-2
@@ -384,7 +384,7 @@ static void tc_device_free(struct tc_device *n)
384
385
#define MAX_WORDS 20
386
387
-int tc_space(char c) {
387
+static inline int tc_space(char c) {
388
switch(c) {
389
case ' ':
390
case '\t':
@@ -397,7 +397,7 @@ int tc_space(char c) {
397
}
398
}
399
400
-void tc_split_words(char *str, char **words, int max_words) {
400
+static void tc_split_words(char *str, char **words, int max_words) {
401
char *s = str;
402
int i = 0;
403
src/plugins_d.c
+141
-39
@@ -15,6 +15,85 @@
15
16
struct plugind *pluginsd_root = NULL;
17
18
+#define MAX_WORDS 20
19
+
20
+static inline int pluginsd_space(char c) {
21
+ switch(c) {
22
+ case ' ':
23
+ case '\t':
24
+ case '\r':
25
+ case '\n':
26
+ case '=':
27
+ return 1;
28
+
29
+ default:
30
+ return 0;
31
+ }
32
+}
33
+
34
+static void pluginsd_split_words(char *str, char **words, int max_words) {
35
+ char *s = str, quote = 0;
36
+ int i = 0;
37
+
38
+ // skip all white space
39
+ while(pluginsd_space(*s)) s++;
40
+
41
+ // check for quote
42
+ if(*s == '\'' || *s == '"') {
43
+ quote = *s; // remember the quote
44
+ s++; // skip the quote
45
+ }
46
+
47
+ // store the first word
48
+ words[i++] = s;
49
+
50
+ // while we have something
51
+ while(*s) {
52
+ // if it is escape
53
+ if(*s == '\\' && s[1]) {
54
+ s += 2;
55
+ continue;
56
+ }
57
+
58
+ // if it is quote
59
+ else if(*s == quote) {
60
+ quote = 0;
61
+ *s = ' ';
62
+ continue;
63
+ }
64
+
65
+ // if it is a space
66
+ else if(quote == 0 && pluginsd_space(*s)) {
67
+
68
+ // terminate the word
69
+ *s++ = '\0';
70
+
71
+ // skip all white space
72
+ while(pluginsd_space(*s)) s++;
73
+
74
+ // check for quote
75
+ if(*s == '\'' || *s == '"') {
76
+ quote = *s; // remember the quote
77
+ s++; // skip the quote
78
+ }
79
+
80
+ // if we reached the end, stop
81
+ if(!*s) break;
82
+
83
+ // store the next word
84
+ if(i < max_words) words[i++] = s;
85
+ else break;
86
+ }
87
+
88
+ // anything else
89
+ else s++;
90
+ }
91
+
92
+ // terminate the words
93
+ while(i < max_words) words[i++] = NULL;
94
+}
95
+
96
+
97
void *pluginsd_worker_thread(void *arg)
98
{
99
struct plugind *cd = (struct plugind *)arg;
@@ -25,6 +104,19 @@ void *pluginsd_worker_thread(void *arg)
104
struct timeval last = {0, 0} , now = {0, 0};
105
#endif
106
107
+ char *words[MAX_WORDS] = { NULL };
108
+ uint32_t SET_HASH = simple_hash("SET");
109
+ uint32_t BEGIN_HASH = simple_hash("BEGIN");
110
+ uint32_t END_HASH = simple_hash("END");
111
+ uint32_t FLUSH_HASH = simple_hash("FLUSH");
112
+ uint32_t CHART_HASH = simple_hash("CHART");
113
+ uint32_t DIMENSION_HASH = simple_hash("DIMENSION");
114
+ uint32_t DISABLE_HASH = simple_hash("DISABLE");
115
+#ifdef DETACH_PLUGINS_FROM_NETDATA
116
+ uint32_t MYPID_HASH = simple_hash("MYPID");
117
+ uint32_t STOPPING_WAKE_ME_UP_PLEASE_HASH = simple_hash("STOPPING_WAKE_ME_UP_PLEASE");
118
+#endif
119
+
120
while(1) {
121
FILE *fp = mypopen(cd->cmd, &cd->pid);
122
if(!fp) {
@@ -33,29 +125,39 @@ void *pluginsd_worker_thread(void *arg)
125
}
126
127
RRDSET *st = NULL;
36
-
128
unsigned long long count = 0;
129
+ char *s;
130
+ uint32_t hash;
131
+
132
while(fgets(line, PLUGINSD_LINE_MAX, fp) != NULL) {
39
- char *p = trim(line);
40
- debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
133
+ line[PLUGINSD_LINE_MAX] = '\0';
134
42
- char *s = qstrsep(&p);
135
+ // debug(D_PLUGINSD, "PLUGINSD: %s: %s", cd->filename, line);
136
44
- if(!s || !*s) continue;
45
- else if(!strcmp(s, "SET")) {
46
- char *t;
47
- while((t = strchr(p, '='))) *t = ' ';
48
-
49
- char *dimension = qstrsep(&p);
50
- char *value = qstrsep(&p);
137
+ pluginsd_split_words(line, words, MAX_WORDS);
138
+ s = words[0];
139
+ if(!s || !*s) {
140
+ // debug(D_PLUGINSD, "PLUGINSD: empty line");
141
+ continue;
142
+ }
143
52
- if(!dimension || !*dimension || !value) {
53
- error("PLUGINSD: '%s' is requesting a SET on chart '%s', like this: 'SET %s = %s'. Disabling it.", cd->fullfilename, st->id, dimension?dimension:"", value?value:"");
144
+ // debug(D_PLUGINSD, "PLUGINSD: words 0='%s' 1='%s' 2='%s' 3='%s' 4='%s' 5='%s' 6='%s' 7='%s' 8='%s' 9='%s'", words[0], words[1], words[2], words[3], words[4], words[5], words[6], words[7], words[8], words[9]);
145
+
146
+ hash = simple_hash(s);
147
+
148
+ if(hash == SET_HASH && !strcmp(s, "SET")) {
149
+ char *dimension = words[1];
150
+ char *value = words[2];
151
+
152
+ if(!dimension || !*dimension) {
153
+ error("PLUGINSD: '%s' is requesting a SET on chart '%s', like this: 'SET %s = %s'. Disabling it.", cd->fullfilename, st->id, dimension?dimension:"<nothing>", value?value:"<nothing>");
154
cd->enabled = 0;
155
kill(cd->pid, SIGTERM);
156
break;
157
}
158
159
+ if(!value || !*value) value = "0";
160
+
161
if(!st) {
162
error("PLUGINSD: '%s' is requesting a SET on dimension %s with value %s, without a BEGIN. Disabling it.", cd->fullfilename, dimension, value);
163
cd->enabled = 0;
@@ -68,9 +170,9 @@ void *pluginsd_worker_thread(void *arg)
170
171
count++;
172
}
71
- else if(!strcmp(s, "BEGIN")) {
72
- char *id = qstrsep(&p);
73
- char *microseconds_txt = qstrsep(&p);
173
+ else if(hash == BEGIN_HASH && !strcmp(s, "BEGIN")) {
174
+ char *id = words[1];
175
+ char *microseconds_txt = words[2];
176
177
if(!id) {
178
error("PLUGINSD: '%s' is requesting a BEGIN without a chart id. Disabling it.", cd->fullfilename);
@@ -94,7 +196,7 @@ void *pluginsd_worker_thread(void *arg)
196
else rrdset_next_plugins(st);
197
}
198
}
97
- else if(!strcmp(s, "END")) {
199
+ else if(hash == END_HASH && !strcmp(s, "END")) {
200
if(!st) {
201
error("PLUGINSD: '%s' is requesting an END, without a BEGIN. Disabling it.", cd->fullfilename);
202
cd->enabled = 0;
@@ -107,27 +209,27 @@ void *pluginsd_worker_thread(void *arg)
209
rrdset_done(st);
210
st = NULL;
211
}
110
- else if(!strcmp(s, "FLUSH")) {
212
+ else if(hash == FLUSH_HASH && !strcmp(s, "FLUSH")) {
213
debug(D_PLUGINSD, "PLUGINSD: '%s' is requesting a FLUSH", cd->fullfilename);
214
st = NULL;
215
}
114
- else if(!strcmp(s, "CHART")) {
216
+ else if(hash == CHART_HASH && !strcmp(s, "CHART")) {
217
st = NULL;
218
117
- char *type = qstrsep(&p);
219
+ char *type = words[1];
220
char *id = NULL;
221
if(type) {
222
id = strchr(type, '.');
223
if(id) { *id = '\0'; id++; }
224
}
123
- char *name = qstrsep(&p);
124
- char *title = qstrsep(&p);
125
- char *units = qstrsep(&p);
126
- char *family = qstrsep(&p);
127
- char *category = qstrsep(&p);
128
- char *chart = qstrsep(&p);
129
- char *priority_s = qstrsep(&p);
130
- char *update_every_s = qstrsep(&p);
225
+ char *name = words[2];
226
+ char *title = words[3];
227
+ char *units = words[4];
228
+ char *family = words[5];
229
+ char *category = words[6];
230
+ char *chart = words[7];
231
+ char *priority_s = words[8];
232
+ char *update_every_s = words[9];
233
234
if(!type || !*type || !id || !*id) {
235
error("PLUGINSD: '%s' is requesting a CHART, without a type.id. Disabling it.", cd->fullfilename);
@@ -169,13 +271,13 @@ void *pluginsd_worker_thread(void *arg)
271
}
272
else debug(D_PLUGINSD, "PLUGINSD: Chart '%s' already exists. Not adding it again.", st->id);
273
}
172
- else if(!strcmp(s, "DIMENSION")) {
173
- char *id = qstrsep(&p);
174
- char *name = qstrsep(&p);
175
- char *algorithm = qstrsep(&p);
176
- char *multiplier_s = qstrsep(&p);
177
- char *divisor_s = qstrsep(&p);
178
- char *hidden = qstrsep(&p);
274
+ else if(hash == DIMENSION_HASH && !strcmp(s, "DIMENSION")) {
275
+ char *id = words[1];
276
+ char *name = words[2];
277
+ char *algorithm = words[3];
278
+ char *multiplier_s = words[4];
279
+ char *divisor_s = words[5];
280
+ char *hidden = words[6];
281
282
if(!id || !*id) {
283
error("PLUGINSD: '%s' is requesting a DIMENSION, without an id. Disabling it.", cd->fullfilename);
@@ -218,21 +320,21 @@ void *pluginsd_worker_thread(void *arg)
320
}
321
else if(st->debug) debug(D_PLUGINSD, "PLUGINSD: dimension %s/%s already exists. Not adding it again.", st->id, id);
322
}
221
- else if(!strcmp(s, "DISABLE")) {
323
+ else if(hash == DISABLE_HASH && !strcmp(s, "DISABLE")) {
324
error("PLUGINSD: '%s' called DISABLE. Disabling it.", cd->fullfilename);
325
cd->enabled = 0;
326
kill(cd->pid, SIGTERM);
327
break;
328
}
329
#ifdef DETACH_PLUGINS_FROM_NETDATA
228
- else if(!strcmp(s, "MYPID")) {
229
- char *pid_s = qstrsep(&p);
330
+ else if(hash == MYPID_HASH && !strcmp(s, "MYPID")) {
331
+ char *pid_s = words[1];
332
pid_t pid = atol(pid_s);
333
334
if(pid) cd->pid = pid;
335
debug(D_PLUGINSD, "PLUGINSD: %s is on pid %d", cd->id, cd->pid);
336
}
235
- else if(!strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE")) {
337
+ else if(hash == STOPPING_WAKE_ME_UP_PLEASE_HASH && !strcmp(s, "STOPPING_WAKE_ME_UP_PLEASE")) {
338
error("PLUGINSD: '%s' (pid %d) called STOPPING_WAKE_ME_UP_PLEASE.", cd->fullfilename, cd->pid);
339
340
gettimeofday(&now, NULL);