From 262f7464fbd838081c85097854afb5ce56e54418 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@1062 a5681a0c-68f1-0310-ab6d-d61299d08faa --- program/configure.ac | 20 ++++++++++++-------- program/src/Makefile.am | 4 ++-- program/src/rrd_create.c | 24 ++++++++++++++++++++++-- program/src/rrd_fetch.c | 21 +++++++++++++++++++++ program/src/rrd_open.c | 13 +++++++++++++ program/src/rrd_update.c | 25 +++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 12 deletions(-) diff --git a/program/configure.ac b/program/configure.ac index 4061795b..8e64c11a 100644 --- a/program/configure.ac +++ b/program/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/program/src/Makefile.am b/program/src/Makefile.am index be51036e..5ed0558d 100644 --- a/program/src/Makefile.am +++ b/program/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/program/src/rrd_create.c b/program/src/rrd_create.c index 70f43312..521c7261 100644 --- a/program/src/rrd_create.c +++ b/program/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/program/src/rrd_fetch.c b/program/src/rrd_fetch.c index 5745892d..7e92c2ca 100644 --- a/program/src/rrd_fetch.c +++ b/program/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/program/src/rrd_open.c b/program/src/rrd_open.c index 08c79848..8f081764 100644 --- a/program/src/rrd_open.c +++ b/program/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/program/src/rrd_update.c b/program/src/rrd_update.c index d5c65c9d..dc1a492b 100644 --- a/program/src/rrd_update.c +++ b/program/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.30.2