apps.plugin optimization to eliminate several unneeded calls
Costa Tsaousis (ktsaou) committed
Jan 24, 2017 at 01:10 UTC
66fd5099afc2cf324cb720af2725d0fb7b6acf12
3 files changed
+170
-106
src/apps_plugin.c
+132
-89
@@ -475,6 +475,8 @@ struct pid_stat {
475
unsigned long long io_collected_usec;
476
unsigned long long last_io_collected_usec;
477
478
+ char *fds_dirname; // the full directory name in /proc/PID/fd
479
+
480
char *stat_filename;
481
char *statm_filename;
482
char *io_filename;
@@ -522,11 +524,12 @@ static inline void del_pid_entry(pid_t pid) {
524
if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
525
if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
526
525
- if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
526
- if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
527
- if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
528
- if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
529
- if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
527
+ freez(all_pids[pid]->fds);
528
+ freez(all_pids[pid]->fds_dirname);
529
+ freez(all_pids[pid]->stat_filename);
530
+ freez(all_pids[pid]->statm_filename);
531
+ freez(all_pids[pid]->io_filename);
532
+ freez(all_pids[pid]->cmdline_filename);
533
freez(all_pids[pid]);
534
535
all_pids[pid] = NULL;
@@ -604,7 +607,8 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
607
if(unlikely(!ff)) goto cleanup;
608
609
// if(set_quotes) procfile_set_quotes(ff, "()");
607
- if(set_quotes) procfile_set_open_close(ff, "(", ")");
610
+ if(unlikely(set_quotes))
611
+ procfile_set_open_close(ff, "(", ")");
612
613
ff = procfile_readall(ff);
614
if(unlikely(!ff)) goto cleanup;
@@ -615,7 +619,8 @@ static inline int read_proc_pid_stat(struct pid_stat *p) {
619
620
// p->pid = str2ul(procfile_lineword(ff, 0, 0+i));
621
618
- strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
622
+ if(unlikely(!p->comm[0]))
623
+ strncpyz(p->comm, procfile_lineword(ff, 0, 1), MAX_COMPARE_NAME);
624
625
// p->state = *(procfile_lineword(ff, 0, 2));
626
p->ppid = (int32_t)str2ul(procfile_lineword(ff, 0, 3));
@@ -1172,74 +1177,106 @@ static inline int file_descriptor_find_or_add(const char *name)
1177
return file_descriptor_set_on_empty_slot(name, hash, type);
1178
}
1179
1180
+static inline void make_all_pid_fds_negative(struct pid_stat *p) {
1181
+ int *fd = p->fds, *end = &p->fds[p->fds_size];
1182
+ while(fd < end) {
1183
+ *fd = -(*fd);
1184
+ fd++;
1185
+ }
1186
+}
1187
+
1188
+static inline void cleanup_negative_pid_fds(struct pid_stat *p) {
1189
+ int *fd = p->fds, *end = &p->fds[p->fds_size];
1190
+ while(fd < end) {
1191
+ if(unlikely(*fd < 0)) {
1192
+ file_descriptor_not_used(-(*fd));
1193
+ *fd++ = 0;
1194
+ }
1195
+ else
1196
+ fd++;
1197
+ }
1198
+}
1199
+
1200
+static inline void zero_pid_fds(struct pid_stat *p, int first, int size) {
1201
+ int *fd = &p->fds[first], *end = &p->fds[first + size];
1202
+ while(fd < end) *fd++ = 0;
1203
+}
1204
+
1205
static inline int read_pid_file_descriptors(struct pid_stat *p) {
1176
- char dirname[FILENAME_MAX+1];
1177
-
1178
- snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
1179
- DIR *fds = opendir(dirname);
1180
- if(fds) {
1181
- int c;
1182
- struct dirent *de;
1183
- char fdname[FILENAME_MAX + 1];
1184
- char linkname[FILENAME_MAX + 1];
1185
-
1186
- // make the array negative
1187
- for(c = 0 ; c < p->fds_size ; c++)
1188
- p->fds[c] = -p->fds[c];
1189
-
1190
- while((de = readdir(fds))) {
1191
- if(strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
1192
- continue;
1206
+ if(unlikely(!p->fds_dirname)) {
1207
+ char dirname[FILENAME_MAX+1];
1208
+ snprintfz(dirname, FILENAME_MAX, "%s/proc/%d/fd", global_host_prefix, p->pid);
1209
+ p->fds_dirname = strdupz(dirname);
1210
+ }
1211
1194
- // check if the fds array is small
1195
- int fdid = (int)str2l(de->d_name);
1196
- if(fdid < 0) continue;
1197
- if(fdid >= p->fds_size) {
1198
- // it is small, extend it
1199
- if(unlikely(debug))
1200
- fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
1212
+ DIR *fds = opendir(p->fds_dirname);
1213
+ if(unlikely(!fds)) return 0;
1214
1202
- p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
1215
+ struct dirent *de;
1216
+ char fdname[FILENAME_MAX + 1];
1217
+ char linkname[FILENAME_MAX + 1];
1218
1204
- // and initialize it
1205
- for(c = p->fds_size ; c < (fdid + MAX_SPARE_FDS) ; c++) p->fds[c] = 0;
1206
- p->fds_size = fdid + MAX_SPARE_FDS;
1207
- }
1219
+ // we make all pid fds negative, so that
1220
+ // we can detect unused file descriptors
1221
+ // at the end, to free them
1222
+ make_all_pid_fds_negative(p);
1223
+
1224
+ while((de = readdir(fds))) {
1225
+ // we need only files with numeric names
1226
+
1227
+ if(unlikely(de->d_name[0] < '0' || de->d_name[0] > '9'))
1228
+ continue;
1229
1209
- if(p->fds[fdid] == 0) {
1210
- // we don't know this fd, get it
1211
-
1212
- sprintf(fdname, "%s/proc/%d/fd/%s", global_host_prefix, p->pid, de->d_name);
1213
- ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1214
- if(l == -1) {
1215
- if(debug || (p->target && p->target->debug)) {
1216
- if(debug || (p->target && p->target->debug))
1217
- error("Cannot read link %s", fdname);
1218
- }
1219
- continue;
1230
+ // get its number
1231
+ int fdid = (int)str2l(de->d_name);
1232
+ if(unlikely(fdid < 0)) continue;
1233
+
1234
+ // check if the fds array is small
1235
+ if(unlikely(fdid >= p->fds_size)) {
1236
+ // it is small, extend it
1237
+
1238
+ if(unlikely(debug))
1239
+ fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + MAX_SPARE_FDS);
1240
+
1241
+ p->fds = reallocz(p->fds, (fdid + MAX_SPARE_FDS) * sizeof(int));
1242
+
1243
+ // and initialize it
1244
+ zero_pid_fds(p, p->fds_size, (fdid + MAX_SPARE_FDS) - p->fds_size);
1245
+ p->fds_size = fdid + MAX_SPARE_FDS;
1246
+ }
1247
+
1248
+ if(unlikely(p->fds[fdid] == 0)) {
1249
+ // we don't know this fd, get it
1250
+
1251
+ sprintf(fdname, "%s/proc/%d/fd/%s", global_host_prefix, p->pid, de->d_name);
1252
+ ssize_t l = readlink(fdname, linkname, FILENAME_MAX);
1253
+ if(unlikely(l == -1)) {
1254
+ if(debug || (p->target && p->target->debug)) {
1255
+ if(debug || (p->target && p->target->debug))
1256
+ error("Cannot read link %s", fdname);
1257
}
1258
+ continue;
1259
+ }
1260
+ else
1261
linkname[l] = '\0';
1222
- file_counter++;
1262
1224
- // if another process already has this, we will get
1225
- // the same id
1226
- p->fds[fdid] = file_descriptor_find_or_add(linkname);
1227
- }
1263
+ file_counter++;
1264
1229
- // else make it positive again, we need it
1230
- // of course, the actual file may have changed, but we don't care so much
1231
- // FIXME: we could compare the inode as returned by readdir dirent structure
1232
- else p->fds[fdid] = -p->fds[fdid];
1265
+ // if another process already has this, we will get
1266
+ // the same id
1267
+ p->fds[fdid] = file_descriptor_find_or_add(linkname);
1268
}
1234
- closedir(fds);
1269
1236
- // remove all the negative file descriptors
1237
- for(c = 0 ; c < p->fds_size ; c++) if(p->fds[c] < 0) {
1238
- file_descriptor_not_used(-p->fds[c]);
1239
- p->fds[c] = 0;
1240
- }
1270
+ // else make it positive again, we need it
1271
+ // of course, the actual file may have changed, but we don't care so much
1272
+ // FIXME: we could compare the inode as returned by readdir dirent structure
1273
+
1274
+ else
1275
+ p->fds[fdid] = -p->fds[fdid];
1276
}
1242
- else return 0;
1277
+
1278
+ closedir(fds);
1279
+ cleanup_negative_pid_fds(p);
1280
1281
return 1;
1282
}
@@ -1594,6 +1631,37 @@ static inline int managed_log(struct pid_stat *p, uint32_t log, int status) {
1631
return status;
1632
}
1633
1634
+static inline void assign_target_to_pid(struct pid_stat *p) {
1635
+ uint32_t hash = simple_hash(p->comm);
1636
+ size_t pclen = strlen(p->comm);
1637
+
1638
+ struct target *w;
1639
+ for(w = apps_groups_root_target; w ; w = w->next) {
1640
+ // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1641
+
1642
+ // find it - 4 cases:
1643
+ // 1. the target is not a pattern
1644
+ // 2. the target has the prefix
1645
+ // 3. the target has the suffix
1646
+ // 4. the target is something inside cmdline
1647
+
1648
+ if(unlikely(( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1649
+ || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1650
+ || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1651
+ || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1652
+ ))) {
1653
+
1654
+ if(w->target) p->target = w->target;
1655
+ else p->target = w;
1656
+
1657
+ if(debug || (p->target && p->target->debug))
1658
+ fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1659
+
1660
+ break;
1661
+ }
1662
+ }
1663
+}
1664
+
1665
static inline int collect_data_for_pid(pid_t pid) {
1666
if(unlikely(pid <= 0 || pid > pid_max)) {
1667
error("Invalid pid %d read (expected 1 to %d). Ignoring process.", pid, pid_max);
@@ -1646,32 +1714,7 @@ static inline int collect_data_for_pid(pid_t pid) {
1714
if(unlikely(debug))
1715
fprintf(stderr, "apps.plugin: \tJust added %d (%s)\n", pid, p->comm);
1716
1649
- uint32_t hash = simple_hash(p->comm);
1650
- size_t pclen = strlen(p->comm);
1651
-
1652
- struct target *w;
1653
- for(w = apps_groups_root_target; w ; w = w->next) {
1654
- // if(debug || (p->target && p->target->debug)) fprintf(stderr, "apps.plugin: \t\tcomparing '%s' with '%s'\n", w->compare, p->comm);
1655
-
1656
- // find it - 4 cases:
1657
- // 1. the target is not a pattern
1658
- // 2. the target has the prefix
1659
- // 3. the target has the suffix
1660
- // 4. the target is something inside cmdline
1661
- if( (!w->starts_with && !w->ends_with && w->comparehash == hash && !strcmp(w->compare, p->comm))
1662
- || (w->starts_with && !w->ends_with && !strncmp(w->compare, p->comm, w->comparelen))
1663
- || (!w->starts_with && w->ends_with && pclen >= w->comparelen && !strcmp(w->compare, &p->comm[pclen - w->comparelen]))
1664
- || (proc_pid_cmdline_is_needed && w->starts_with && w->ends_with && strstr(p->cmdline, w->compare))
1665
- ) {
1666
- if(w->target) p->target = w->target;
1667
- else p->target = w;
1668
-
1669
- if(debug || (p->target && p->target->debug))
1670
- fprintf(stderr, "apps.plugin: \t\t%s linked to target %s\n", p->comm, p->target->name);
1671
-
1672
- break;
1673
- }
1674
- }
1717
+ assign_target_to_pid(p);
1718
}
1719
1720
// --------------------------------------------------------------------
src/procfile.c
+34
-16
@@ -15,6 +15,25 @@ size_t procfile_max_lines = PFLINES_INCREASE_STEP;
15
size_t procfile_max_words = PFWORDS_INCREASE_STEP;
16
size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER;
17
18
+
19
+// ----------------------------------------------------------------------------
20
+
21
+char *procfile_filename(procfile *ff) {
22
+ char buffer[FILENAME_MAX + 1];
23
+ snprintfz(buffer, FILENAME_MAX, "/proc/self/fd/%d", ff->fd);
24
+
25
+ ssize_t l = readlink(buffer, ff->filename, FILENAME_MAX);
26
+ if(unlikely(l == -1))
27
+ snprintfz(ff->filename, FILENAME_MAX, "unknown filename for fd %d", ff->fd);
28
+ else
29
+ ff->filename[l] = '\0';
30
+
31
+ // on non-linux systems, something like this will be needed
32
+ // fcntl(ff->fd, F_GETPATH, ff->filename)
33
+
34
+ return ff->filename;
35
+}
36
+
37
// ----------------------------------------------------------------------------
38
// An array of words
39
@@ -114,7 +133,7 @@ static inline void pflines_free(pflines *fl) {
133
#define PF_CHAR_IS_CLOSE 'C'
134
135
void procfile_close(procfile *ff) {
117
- debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
136
+ debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", procfile_filename(ff));
137
138
if(likely(ff->lines)) pflines_free(ff->lines);
139
if(likely(ff->words)) pfwords_free(ff->words);
@@ -250,26 +269,24 @@ static inline void procfile_parser(procfile *ff) {
269
}
270
271
procfile *procfile_readall(procfile *ff) {
253
- debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
254
-
255
- ssize_t r = 1;
256
- ff->len = 0;
272
+ // debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename);
273
258
- while(likely(r > 0)) {
274
+ ff->len = 0; // zero the used size
275
+ ssize_t r = 1; // read at least once
276
+ while(r > 0) {
277
ssize_t s = ff->len;
278
ssize_t x = ff->size - s;
279
280
if(unlikely(!x)) {
263
- debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
264
-
281
+ debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", procfile_filename(ff));
282
ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
283
ff->size += PROCFILE_INCREMENT_BUFFER;
284
}
285
269
- debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", ff->filename, s, ff->size - s);
286
+ debug(D_PROCFILE, "Reading file '%s', from position %ld with length %lu", procfile_filename(ff), s, ff->size - s);
287
r = read(ff->fd, &ff->data[s], ff->size - s);
288
if(unlikely(r == -1)) {
272
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
289
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot read from file '%s'", procfile_filename(ff));
290
procfile_close(ff);
291
return NULL;
292
}
@@ -277,9 +294,9 @@ procfile *procfile_readall(procfile *ff) {
294
ff->len += r;
295
}
296
280
- debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
297
+ // debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
298
if(unlikely(lseek(ff->fd, 0, SEEK_SET) == -1)) {
282
- if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
299
+ if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) error(PF_PREFIX ": Cannot rewind on file '%s'.", procfile_filename(ff));
300
procfile_close(ff);
301
return NULL;
302
}
@@ -294,7 +311,7 @@ procfile *procfile_readall(procfile *ff) {
311
if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len;
312
}
313
297
- debug(D_PROCFILE, "File '%s' updated.", ff->filename);
314
+ // debug(D_PROCFILE, "File '%s' updated.", ff->filename);
315
return ff;
316
}
317
@@ -379,7 +396,8 @@ procfile *procfile_open(const char *filename, const char *separators, uint32_t f
396
397
size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
398
procfile *ff = mallocz(sizeof(procfile) + size);
382
- strncpyz(ff->filename, filename, FILENAME_MAX);
399
+
400
+ //strncpyz(ff->filename, filename, FILENAME_MAX);
401
402
ff->fd = fd;
403
ff->size = size;
@@ -406,7 +424,7 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa
424
return NULL;
425
}
426
409
- strncpyz(ff->filename, filename, FILENAME_MAX);
427
+ //strncpyz(ff->filename, filename, FILENAME_MAX);
428
429
ff->flags = flags;
430
@@ -423,7 +441,7 @@ void procfile_print(procfile *ff) {
441
size_t lines = procfile_lines(ff), l;
442
char *s;
443
426
- debug(D_PROCFILE, "File '%s' with %zu lines and %zu words", ff->filename, ff->lines->len, ff->words->len);
444
+ debug(D_PROCFILE, "File '%s' with %zu lines and %zu words", procfile_filename(ff), ff->lines->len, ff->words->len);
445
446
for(l = 0; likely(l < lines) ;l++) {
447
size_t words = procfile_linewords(ff, l);
src/procfile.h
+4
-1
@@ -59,7 +59,8 @@ typedef struct {
59
#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001
60
61
typedef struct {
62
- char filename[FILENAME_MAX + 1];
62
+ char filename[FILENAME_MAX + 1]; // not populated until profile_filename() is called
63
+
64
uint32_t flags;
65
int fd; // the file desriptor
66
size_t len; // the bytes we have placed into data
@@ -89,6 +90,8 @@ extern void procfile_print(procfile *ff);
90
extern void procfile_set_quotes(procfile *ff, const char *quotes);
91
extern void procfile_set_open_close(procfile *ff, const char *open, const char *close);
92
93
+extern char *procfile_filename(procfile *ff);
94
+
95
// ----------------------------------------------------------------------------
96
97
// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far