diff options
Diffstat (limited to '')
-rw-r--r-- | src/libnetdata/procfile/README.md | 9 | ||||
-rw-r--r-- | src/libnetdata/procfile/procfile.c | 67 | ||||
-rw-r--r-- | src/libnetdata/procfile/procfile.h | 27 |
3 files changed, 77 insertions, 26 deletions
diff --git a/src/libnetdata/procfile/README.md b/src/libnetdata/procfile/README.md index 9e737a51..faa00c6a 100644 --- a/src/libnetdata/procfile/README.md +++ b/src/libnetdata/procfile/README.md @@ -1,12 +1,3 @@ -<!-- -title: "PROCFILE" -custom_edit_url: https://github.com/netdata/netdata/edit/master/src/libnetdata/procfile/README.md -sidebar_label: "Procfile" -learn_status: "Published" -learn_topic_type: "Tasks" -learn_rel_path: "Developers/libnetdata" ---> - # PROCFILE procfile is a library for reading text data files (i.e `/proc` files) in the fastest possible way. diff --git a/src/libnetdata/procfile/procfile.c b/src/libnetdata/procfile/procfile.c index 2b7eeeb5..fb6b0f8c 100644 --- a/src/libnetdata/procfile/procfile.c +++ b/src/libnetdata/procfile/procfile.c @@ -10,14 +10,23 @@ int procfile_open_flags = O_RDONLY | O_CLOEXEC; -int procfile_adaptive_initial_allocation = 0; - // if adaptive allocation is set, these store the // max values we have seen so far -size_t procfile_max_lines = PFLINES_INCREASE_STEP; -size_t procfile_max_words = PFWORDS_INCREASE_STEP; -size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER; - +static bool procfile_adaptive_initial_allocation = false; +static size_t procfile_max_lines = PFLINES_INCREASE_STEP; +static size_t procfile_max_words = PFWORDS_INCREASE_STEP; +static size_t procfile_max_allocation = PROCFILE_INCREMENT_BUFFER; + +void procfile_set_adaptive_allocation(bool enable, size_t bytes, size_t lines, size_t words) { + procfile_adaptive_initial_allocation = enable; + + if(bytes > procfile_max_allocation) + procfile_max_allocation = bytes; + if(lines > procfile_max_lines) + procfile_max_lines = lines; + if(words > procfile_max_words) + procfile_max_words = words; +} // ---------------------------------------------------------------------------- @@ -59,6 +68,8 @@ static inline void procfile_words_add(procfile *ff, char *str) { ff->words = fw = reallocz(fw, sizeof(pfwords) + (fw->size + wanted) * sizeof(char *)); fw->size += wanted; + ff->stats.memory += wanted * sizeof(char *); + ff->stats.resizes++; } fw->words[fw->len++] = str; @@ -92,7 +103,7 @@ static inline void procfile_words_free(pfwords *fw) { // An array of lines NEVERNULL -static inline size_t *procfile_lines_add(procfile *ff) { +static inline uint32_t *procfile_lines_add(procfile *ff) { // netdata_log_debug(D_PROCFILE, PF_PREFIX ": adding line %d at word %d", fl->len, first_word); pflines *fl = ff->lines; @@ -104,6 +115,8 @@ static inline size_t *procfile_lines_add(procfile *ff) { ff->lines = fl = reallocz(fl, sizeof(pflines) + (fl->size + wanted) * sizeof(ffline)); fl->size += wanted; + ff->stats.memory += wanted * sizeof(ffline); + ff->stats.resizes++; } ffline *ffl = &fl->lines[fl->len++]; @@ -168,7 +181,7 @@ static void procfile_parser(procfile *ff) { char quote = 0; // the quote character - only when in quoted string size_t opened = 0; // counts the number of open parenthesis - size_t *line_words = procfile_lines_add(ff); + uint32_t *line_words = procfile_lines_add(ff); while(s < e) { PF_CHAR_TYPE ct = separators[(unsigned char)(*s)]; @@ -230,8 +243,12 @@ static void procfile_parser(procfile *ff) { } else if(likely(ct == PF_CHAR_IS_OPEN)) { if(s == t) { + if(!opened) + t = ++s; + else + ++s; + opened++; - t = ++s; } else if(opened) { opened++; @@ -275,6 +292,8 @@ static void procfile_parser(procfile *ff) { } procfile *procfile_readall(procfile *ff) { + if(!ff) return NULL; + // netdata_log_debug(D_PROCFILE, PF_PREFIX ": Reading file '%s'.", ff->filename); ff->len = 0; // zero the used size @@ -291,9 +310,12 @@ procfile *procfile_readall(procfile *ff) { netdata_log_debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s' by %zu bytes.", procfile_filename(ff), wanted); ff = reallocz(ff, sizeof(procfile) + ff->size + wanted); ff->size += wanted; + ff->stats.memory += wanted; + ff->stats.resizes++; } - netdata_log_debug(D_PROCFILE, "Reading file '%s', from position %zd with length %zd", procfile_filename(ff), s, (ssize_t)(ff->size - s)); + // netdata_log_info("Reading file '%s', from position %zd with length %zd", procfile_filename(ff), s, (ssize_t)(ff->size - s)); + ff->stats.reads++; r = read(ff->fd, &ff->data[s], ff->size - s); if(unlikely(r == -1)) { if(unlikely(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO))) collector_error(PF_PREFIX ": Cannot read from file '%s' on fd %d", procfile_filename(ff), ff->fd); @@ -303,6 +325,9 @@ procfile *procfile_readall(procfile *ff) { return NULL; } + if((ssize_t)ff->stats.max_read_size < r) + ff->stats.max_read_size = r; + ff->len += r; } @@ -325,6 +350,17 @@ procfile *procfile_readall(procfile *ff) { if(unlikely(ff->words->len > procfile_max_words)) procfile_max_words = ff->words->len; } + if(ff->stats.max_source_bytes < ff->len) + ff->stats.max_source_bytes = ff->len; + + if(ff->stats.max_lines < ff->lines->len) + ff->stats.max_lines = ff->lines->len; + + if(ff->stats.max_words < ff->words->len) + ff->stats.max_words = ff->words->len; + + ff->stats.total_read_bytes += ff->len; + // netdata_log_debug(D_PROCFILE, "File '%s' updated.", ff->filename); return ff; } @@ -429,10 +465,18 @@ procfile *procfile_open(const char *filename, const char *separators, uint32_t f ff->size = size; ff->len = 0; ff->flags = flags; + ff->stats.opens = 1; + ff->stats.reads = ff->stats.resizes = 0; + ff->stats.max_lines = ff->stats.max_words = ff->stats.max_source_bytes = 0; + ff->stats.total_read_bytes = ff->stats.max_read_size = 0; ff->lines = procfile_lines_create(); ff->words = procfile_words_create(); + ff->stats.memory = sizeof(procfile) + size + + (sizeof(pflines) + ff->lines->size * sizeof(ffline)) + + (sizeof(pfwords) + ff->words->size * sizeof(char *)); + procfile_set_separators(ff, separators); netdata_log_debug(D_PROCFILE, "File '%s' opened.", filename); @@ -452,6 +496,7 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa procfile_close(ff); return NULL; } + ff->stats.opens++; // netdata_log_info("PROCFILE: opened '%s' on fd %d", filename, ff->fd); @@ -479,7 +524,7 @@ void procfile_print(procfile *ff) { for(l = 0; likely(l < lines) ;l++) { size_t words = procfile_linewords(ff, l); - netdata_log_debug(D_PROCFILE, " line %zu starts at word %zu and has %zu words", l, ff->lines->lines[l].first, ff->lines->lines[l].words); + netdata_log_debug(D_PROCFILE, " line %zu starts at word %zu and has %zu words", l, (size_t)ff->lines->lines[l].first, (size_t)ff->lines->lines[l].words); size_t w; for(w = 0; likely(w < words) ;w++) { diff --git a/src/libnetdata/procfile/procfile.h b/src/libnetdata/procfile/procfile.h index 8db5b45f..25b97698 100644 --- a/src/libnetdata/procfile/procfile.h +++ b/src/libnetdata/procfile/procfile.h @@ -19,9 +19,8 @@ typedef struct { // An array of lines typedef struct { - size_t words; // how many words this line has - size_t first; // the id of the first word of this line - // in the words array + uint32_t words; // how many words this line has + uint32_t first; // the id of the first word of this line in the words array } ffline; typedef struct { @@ -35,7 +34,7 @@ typedef struct { // The procfile #define PROCFILE_FLAG_DEFAULT 0x00000000 // To store inside `collector.log` -#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001 // Do not store nothing +#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001 // Do not log anything #define PROCFILE_FLAG_ERROR_ON_ERROR_LOG 0x00000002 // Store inside `error.log` typedef enum __attribute__ ((__packed__)) procfile_separator { @@ -47,7 +46,22 @@ typedef enum __attribute__ ((__packed__)) procfile_separator { PF_CHAR_IS_CLOSE } PF_CHAR_TYPE; +struct procfile_stats { + size_t opens; + size_t reads; + size_t resizes; + size_t memory; + size_t total_read_bytes; + size_t max_source_bytes; + size_t max_lines; + size_t max_words; + size_t max_read_size; +}; + + typedef struct procfile { + // this structure is malloc'd (you need to initialize it at procfile_open() + char *filename; // not populated until procfile_filename() is called uint32_t flags; int fd; // the file descriptor @@ -56,6 +70,7 @@ typedef struct procfile { pflines *lines; pfwords *words; PF_CHAR_TYPE separators[256]; + struct procfile_stats stats; char data[]; // allocated buffer to keep file contents } procfile; @@ -85,8 +100,8 @@ char *procfile_filename(procfile *ff); // set to the O_XXXX flags, to have procfile_open and procfile_reopen use them when opening proc files extern int procfile_open_flags; -// set this to 1, to have procfile adapt its initial buffer allocation to the max allocation used so far -extern int procfile_adaptive_initial_allocation; +// call this with true and the expected initial sizes to allow procfile learn the sizes needed +void procfile_set_adaptive_allocation(bool enable, size_t bytes, size_t lines, size_t words); // return the number of lines present #define procfile_lines(ff) ((ff)->lines->len) |