Code

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 4061795badf2e6595df1a3949f7e9acfe3bf2760..8e64c11a93831303510248901aa37838b6bc4c7f 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 be51036ed35d4f504432d8fb6ad92f3c09902990..5ed0558d02444018d94ce542a548f9c0b7bc241c 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 70f43312def3aa3b10c9f15d665295b7300b7313..521c72611488f1c4e5fc68d28d357ac94b6e0fab 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 5745892df99522ec6e75862d3d163a3a78e810b5..7e92c2caeadb1cf42ac9c026bf1dc586c82e1668 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 08c798482e94eb4349cd183ad2add4b3f7b2c9f7..8f08176494fe48f01b6f889f491a28209096603a 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 d5c65c9dbe505dc7437d10e3542b16afdb38f9d0..dc1a492bfdfeeba8139f8497f48c5454718b54c2 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);