From f3df7df77761c610c9ba328fac01619f4e7b563f Mon Sep 17 00:00:00 2001 From: oetiker Date: Thu, 17 May 2007 08:44:06 +0000 Subject: [PATCH] added posix_fadvise support (untested) ... this should help performance by stopping read-ahead and droping buffer cache for all rrd data except the file header portion. Newly created files are fdsynced to disk and released from cache after creation, to soften the blow on buffer cache by creating new rrds. git-svn-id: svn://svn.oetiker.ch/rrdtool/branches/1.2/program@1062 a5681a0c-68f1-0310-ab6d-d61299d08faa --- configure.ac | 20 ++++++++++++-------- src/Makefile.am | 4 ++-- src/rrd_create.c | 24 ++++++++++++++++++++++-- src/rrd_fetch.c | 21 +++++++++++++++++++++ src/rrd_open.c | 13 +++++++++++++ src/rrd_update.c | 25 +++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 4061795..8e64c11 100644 --- a/configure.ac +++ b/configure.ac @@ -56,7 +56,7 @@ AH_BOTTOM([ /* define strrchr, strchr and memcpy, memmove in terms of bsd funcs make sure you are NOT using bcopy, index or rindex in the code */ -#if STDC_HEADERS +#ifdef STDC_HEADERS # include #else # ifndef HAVE_STRCHR @@ -70,30 +70,34 @@ char *strchr (), *strrchr (); # endif #endif +/* enable posix_fadvise on linux */ +#ifdef HAVE_POSIX_FADVISE +#define __USE_XOPEN2K 1 +#endif -#if NO_NULL_REALLOC +#ifdef NO_NULL_REALLOC # define rrd_realloc(a,b) ( (a) == NULL ? malloc( (b) ) : realloc( (a) , (b) )) #else # define rrd_realloc(a,b) realloc((a), (b)) #endif -#if NEED_MALLOC_MALLOC_H +#ifdef NEED_MALLOC_MALLOC_H # include #endif -#if HAVE_MATH_H +#ifdef HAVE_MATH_H # include #endif -#if HAVE_FLOAT_H +#ifdef HAVE_FLOAT_H # include #endif -#if HAVE_IEEEFP_H +#ifdef HAVE_IEEEFP_H # include #endif -#if HAVE_FP_CLASS_H +#ifdef HAVE_FP_CLASS_H # include #endif @@ -243,7 +247,7 @@ AC_C_BIGENDIAN dnl for each function found we get a definition in config.h dnl of the form HAVE_FUNCTION -AC_CHECK_FUNCS(tzset mbstowcs opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday) +AC_CHECK_FUNCS(tzset mbstowcs opendir readdir chdir chroot getuid setlocale strerror strerror_r snprintf vsnprintf fpclass class fp_class isnan memmove strchr mktime getrusage gettimeofday posix_fadvise) if test "x$enable_mmap" = xyes; then diff --git a/src/Makefile.am b/src/Makefile.am index be51036..5ed0558 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -102,11 +102,11 @@ librrd_la_LIBADD = librrdupd.la $(ALL_LIBS) # your package will not be binary compatible with any other release. # # see http://www.gnu.org/software/libtool/manual.html#SEC32 for explanation -librrd_la_LDFLAGS = -version-info 2:10:0 +librrd_la_LDFLAGS = -version-info 2:11:0 librrd_th_la_SOURCES = $(UPD_C_FILES) $(RRD_C_FILES) rrd_thread_safe.c librrd_th_la_CFLAGS = $(MULTITHREAD_CFLAGS) -librrd_th_la_LDFLAGS = $(MULTITHREAD_LDFLAGS) -version-info 2:8:0 +librrd_th_la_LDFLAGS = $(MULTITHREAD_LDFLAGS) -version-info 2:11:0 librrd_th_la_LIBADD = $(ALL_LIBS) include_HEADERS = rrd.h diff --git a/src/rrd_create.c b/src/rrd_create.c index 70f4331..521c726 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -553,7 +553,9 @@ rrd_create_fn(const char *file_name, rrd_t *rrd) FILE *rrd_file; rrd_value_t *unknown; int unkn_cnt; - + + long rrd_head_size; + if ((rrd_file = fopen(file_name,"wb")) == NULL ) { rrd_set_error("creating '%s': %s",file_name, rrd_strerror(errno)); free(rrd->stat_head); @@ -658,7 +660,8 @@ rrd_create_fn(const char *file_name, rrd_t *rrd) rrd->rra_ptr->cur_row = rrd->rra_def[i].row_cnt - 1; fwrite( rrd->rra_ptr, sizeof(rra_ptr_t),1,rrd_file); } - + rrd_head_size = ftell(rrd_file); + /* write the empty data area */ if ((unknown = (rrd_value_t *)malloc(512 * sizeof(rrd_value_t))) == NULL) { rrd_set_error("allocating unknown"); @@ -687,6 +690,23 @@ rrd_create_fn(const char *file_name, rrd_t *rrd) return(-1); } +#ifdef POSIX_FADVISE + /* this file is not going to be read again any time + soon, so we drop everything except the header portion from + the buffer cache. for this to work, we have to fdsync the file + first though. This will not be all that fast, but 'good' data + like other rrdfiles headers will stay in cache. Now this only works if creating + a single rrd file is not too large, but I assume this should not be the case + in general. Otherwhise we would have to sync and release while writing all + the unknown data. */ + fdatasync(fileno(rrd_file)); + if (0 != posix_fadvise(fileno(rrd_file), rrd_head_size, 0, POSIX_FADV_DONTNEED)) { + rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",file_name, rrd_strerror(errno)); + fclose(rrd_file); + return(-1); + } +#endif + fclose(rrd_file); rrd_free(rrd); return (0); diff --git a/src/rrd_fetch.c b/src/rrd_fetch.c index 5745892..7e92c2c 100644 --- a/src/rrd_fetch.c +++ b/src/rrd_fetch.c @@ -205,6 +205,7 @@ rrd_fetch_fn( rrd_t rrd; rrd_value_t *data_ptr; unsigned long rows; + long rrd_head_size; #ifdef DEBUG fprintf(stderr,"Entered rrd_fetch_fn() searching for the best match\n"); @@ -214,6 +215,8 @@ fprintf(stderr,"Looking for: start %10lu end %10lu step %5lu\n", if(rrd_open(filename,&in_file,&rrd, RRD_READONLY)==-1) return(-1); + + rrd_head_size = ftell(in_file); /* when was the really last update of this file ? */ @@ -453,6 +456,16 @@ fprintf(stderr,"partial match, not best\n"); fclose(in_file); return(-1); } +#ifdef POSIX_FADVISE + /* don't pollute the buffer cache with data read from the file. We do this while reading to + keep damage minimal */ + if (0 != posix_fadvise(fileno(in_file), rrd_head_size, ftell(in_file), POSIX_FADV_DONTNEED)) { + rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",file_name, rrd_strerror(errno)); + fclose(in_file); + return(-1); + } +#endif + #ifdef DEBUG fprintf(stderr,"post fetch %li -- ",i); for(ii=0;ii<*ds_cnt;ii++) @@ -467,6 +480,14 @@ fprintf(stderr,"partial match, not best\n"); } rrd_free(&rrd); +#ifdef POSIX_FADVISE + /* and just to be sure we drop everything except the header at the end */ + if (0 != posix_fadvise(fileno(in_file), rrd_head_size, 0, POSIX_FADV_DONTNEED)) { + rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",file_name, rrd_strerror(errno)); + fclose(in_file); + return(-1); + } +#endif fclose(in_file); return(0); } diff --git a/src/rrd_open.c b/src/rrd_open.c index 08c7984..8f08176 100644 --- a/src/rrd_open.c +++ b/src/rrd_open.c @@ -87,6 +87,19 @@ rrd_open(const char *file_name, FILE **in_file, rrd_t *rrd, int rdwr) rrd_set_error("opening '%s': %s",file_name, rrd_strerror(errno)); return (-1); } + +#ifdef POSIX_FADVISE + /* In general we need no read-ahead when dealing with rrd_files. + When we stop reading, it is highly unlikely that we start up again. + In this manner we actually save time and diskaccess (and buffer cache). + Thanks to Dave Plonka for the Idea of using POSIX_FADV_RANDOM here. */ + if (0 != posix_fadvise(fileno(*in_file), 0, 0, POSIX_FADV_RANDOM)) { + rrd_set_error("setting POSIX_FADV_RANDOM on '%s': %s",file_name, rrd_strerror(errno)); + fclose(*in_file); + return(-1); + } +#endif + /* if (rdwr == RRD_READWRITE) { diff --git a/src/rrd_update.c b/src/rrd_update.c index d5c65c9..dc1a492 100644 --- a/src/rrd_update.c +++ b/src/rrd_update.c @@ -261,6 +261,7 @@ _rrd_update(const char *filename, const char *tmplt, int argc, const char **argv rpnstack_t rpnstack; /* used for COMPUTE DS */ int version; /* rrd version */ char *endptr; /* used in the conversion */ + #ifdef HAVE_MMAP void *rrd_mmaped_file; unsigned long rrd_filesize; @@ -280,6 +281,7 @@ _rrd_update(const char *filename, const char *tmplt, int argc, const char **argv if(rrd_open(filename,&rrd_file,&rrd, RRD_READWRITE)==-1){ return -1; } + /* initialize time */ version = atoi(rrd.stat_head->version); gettimeofday(&tmp_time, 0); @@ -1396,6 +1398,19 @@ _rrd_update(const char *filename, const char *tmplt, int argc, const char **argv fclose(rrd_file); return(-1); } +#ifdef POSIX_FADVISE + + /* with update we have write ops, so they will probably not be done by now, this means + the buffers will not get freed. But calling this for the whole file - header + will let the data off the hook as soon as it is written when if it is from a previous + update cycle. Calling fdsync to force things is much too hard here. */ + + if (0 != posix_fadvise(fileno(in_file), rra_begin, 0, POSIX_FADV_DONTNEED)) { + rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",file_name, rrd_strerror(errno)); + fclose(in_file); + return(-1); + } +#endif /* OK now close the files and free the memory */ if(fclose(rrd_file) != 0){ @@ -1416,6 +1431,8 @@ _rrd_update(const char *filename, const char *tmplt, int argc, const char **argv if (schedule_smooth) { rrd_file = fopen(filename,"rb+"); + + rra_start = rra_begin; for (i = 0; i < rrd.stat_head -> rra_cnt; ++i) { @@ -1432,6 +1449,14 @@ _rrd_update(const char *filename, const char *tmplt, int argc, const char **argv rra_start += rrd.rra_def[i].row_cnt *rrd.stat_head->ds_cnt*sizeof(rrd_value_t); } +#ifdef POSIX_FADVISE + /* same procedure as above ... */ + if (0 != posix_fadvise(fileno(in_file), rrd_head_size, 0, POSIX_FADV_DONTNEED)) { + rrd_set_error("setting POSIX_FADV_DONTNEED on '%s': %s",file_name, rrd_strerror(errno)); + fclose(in_file); + return(-1); + } +#endif fclose(rrd_file); } rrd_free(&rrd); -- 2.11.0