added posix_fadvise support (untested) ... this should help performance by
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Thu, 17 May 2007 08:44:06 +0000 (08:44 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Thu, 17 May 2007 08:44:06 +0000 (08:44 +0000)
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
src/Makefile.am
src/rrd_create.c
src/rrd_fetch.c
src/rrd_open.c
src/rrd_update.c

index 4061795..8e64c11 100644 (file)
@@ -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 <string.h>
 #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 <malloc/malloc.h>
 #endif
 
-#if HAVE_MATH_H
+#ifdef HAVE_MATH_H
 #  include <math.h>
 #endif
 
-#if HAVE_FLOAT_H
+#ifdef HAVE_FLOAT_H
 #  include <float.h>
 #endif
 
-#if HAVE_IEEEFP_H
+#ifdef HAVE_IEEEFP_H
 #  include <ieeefp.h>
 #endif
 
-#if HAVE_FP_CLASS_H
+#ifdef HAVE_FP_CLASS_H
 #  include <fp_class.h>
 #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
index be51036..5ed0558 100644 (file)
@@ -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
index 70f4331..521c726 100644 (file)
@@ -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);
index 5745892..7e92c2c 100644 (file)
@@ -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);
 }
index 08c7984..8f08176 100644 (file)
@@ -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)
         {
index d5c65c9..dc1a492 100644 (file)
@@ -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);