@cryptotaxi247 / netdata-1 / commits / a3c28f5df

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);