added percentnan (VDEF PERCENT variant that ignores NAN) -- patch by Martin Sperl
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Wed, 14 Jan 2009 07:22:09 +0000 (07:22 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Wed, 14 Jan 2009 07:22:09 +0000 (07:22 +0000)
git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1732 a5681a0c-68f1-0310-ab6d-d61299d08faa

NEWS
doc/rrdgraph_rpn.pod
src/rrd_graph.c
src/rrd_graph.h

diff --git a/NEWS b/NEWS
index b31f0fd..2c26f68 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -14,3 +14,7 @@ RRDdump
 -------
 * no more spaces in output
 * additional option: --header {none,xsd,dtd}
+
+RRDgraph
+--------
+* VDEF PERCENTNAN (PRECENT that ignores NAN)
index 21661ba..de44c0b 100644 (file)
@@ -357,12 +357,13 @@ the number of seconds.
 
 Example: C<VDEF:total=mydata,TOTAL>
 
-=item PERCENT
+=item PERCENT, PERCENTNAN
 
 This should follow a B<DEF> or B<CDEF> I<vname>. The I<vname> is popped,
 another number is popped which is a certain percentage (0..100). The
 data set is then sorted and the value returned is chosen such that
 I<percentage> percent of the values is lower or equal than the result.
+For PERCENTNAN I<Unknown> values are ignored, but for PERCENT
 I<Unknown> values are considered lower than any finite number for this
 purpose so if this operator returns an I<unknown> you have quite a lot
 of them in your data.  B<Inf>inite numbers are lesser, or more, than the
@@ -370,6 +371,7 @@ finite numbers and are always more than the I<Unknown> numbers.
 (NaN E<lt> -INF E<lt> finite values E<lt> INF)
 
 Example: C<VDEF:perc95=mydata,95,PERCENT>
+         C<VDEF:percnan95=mydata,95,PERCENTNAN>
 
 =item LSLSLOPE, LSLINT, LSLCORREL
 
index 613446f..40539b3 100644 (file)
@@ -4586,6 +4586,8 @@ int vdef_parse(
     }
     if (!strcmp("PERCENT", func))
         gdes->vf.op = VDEF_PERCENT;
+    else if (!strcmp("PERCENTNAN", func))
+        gdes->vf.op = VDEF_PERCENTNAN;
     else if (!strcmp("MAXIMUM", func))
         gdes->vf.op = VDEF_MAXIMUM;
     else if (!strcmp("AVERAGE", func))
@@ -4613,6 +4615,7 @@ int vdef_parse(
     };
     switch (gdes->vf.op) {
     case VDEF_PERCENT:
+    case VDEF_PERCENTNAN:
         if (isnan(param)) { /* no parameter given */
             rrd_set_error
                 ("Function '%s' needs parameter in VDEF '%s'\n",
@@ -4697,6 +4700,34 @@ int vdef_calc(
 #endif
     }
         break;
+    case VDEF_PERCENTNAN:{
+        rrd_value_t *array;
+        int       field;
+       /* count number of "valid" values */
+       int nancount=0;
+       for (step = 0; step < steps; step++) {
+         if (!isnan(data[step * src->ds_cnt])) { nancount++; }
+       }
+       /* and allocate it */
+        if ((array = (rrd_value_t*)malloc(nancount * sizeof(double))) == NULL) {
+            rrd_set_error("malloc VDEV_PERCENT");
+            return -1;
+        }
+       /* and fill it in */
+       field=0;
+        for (step = 0; step < steps; step++) {
+           if (!isnan(data[step * src->ds_cnt])) {
+                array[field] = data[step * src->ds_cnt];
+               field++;
+            }
+        }
+        qsort(array, nancount, sizeof(double), vdef_percent_compar);
+        field = (nancount - 1) * dst->vf.param / 100;
+        dst->vf.val = array[field];
+        dst->vf.when = 0;   /* no time component */
+        free(array);
+    }
+        break;
     case VDEF_MAXIMUM:
         step = 0;
         while (step != steps && isnan(data[step * src->ds_cnt]))
index 25e9db2..cc36c25 100644 (file)
@@ -70,6 +70,7 @@ enum vdef_op_en {
         , VDEF_LSLSLOPE /* least squares line slope */
         , VDEF_LSLINT   /* least squares line y_intercept */
         , VDEF_LSLCORREL    /* least squares line correlation coefficient */
+        , VDEF_PERCENTNAN  /* Nth percentile ignoring NAN*/
 };
 enum text_prop_en { 
     TEXT_PROP_DEFAULT = 0,  /* default settings */