13b6c3722Schristos /*
23b6c3722Schristos * util/timehist.c - make histogram of time values.
33b6c3722Schristos *
43b6c3722Schristos * Copyright (c) 2007, NLnet Labs. All rights reserved.
53b6c3722Schristos *
63b6c3722Schristos * This software is open source.
73b6c3722Schristos *
83b6c3722Schristos * Redistribution and use in source and binary forms, with or without
93b6c3722Schristos * modification, are permitted provided that the following conditions
103b6c3722Schristos * are met:
113b6c3722Schristos *
123b6c3722Schristos * Redistributions of source code must retain the above copyright notice,
133b6c3722Schristos * this list of conditions and the following disclaimer.
143b6c3722Schristos *
153b6c3722Schristos * Redistributions in binary form must reproduce the above copyright notice,
163b6c3722Schristos * this list of conditions and the following disclaimer in the documentation
173b6c3722Schristos * and/or other materials provided with the distribution.
183b6c3722Schristos *
193b6c3722Schristos * Neither the name of the NLNET LABS nor the names of its contributors may
203b6c3722Schristos * be used to endorse or promote products derived from this software without
213b6c3722Schristos * specific prior written permission.
223b6c3722Schristos *
233b6c3722Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
243b6c3722Schristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
253b6c3722Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
263b6c3722Schristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
273b6c3722Schristos * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
283b6c3722Schristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
293b6c3722Schristos * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
303b6c3722Schristos * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
313b6c3722Schristos * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
323b6c3722Schristos * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
333b6c3722Schristos * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
343b6c3722Schristos */
353b6c3722Schristos
363b6c3722Schristos /**
373b6c3722Schristos * \file
383b6c3722Schristos *
393b6c3722Schristos * This file contains functions to make a histogram of time values.
403b6c3722Schristos */
413b6c3722Schristos #include "config.h"
423b6c3722Schristos #ifdef HAVE_TIME_H
433b6c3722Schristos #include <time.h>
443b6c3722Schristos #endif
453b6c3722Schristos #include <sys/time.h>
463b6c3722Schristos #include <sys/types.h>
473b6c3722Schristos #include "util/timehist.h"
483b6c3722Schristos #include "util/log.h"
49*91f7d55fSchristos #include "util/timeval_func.h"
503b6c3722Schristos
513b6c3722Schristos /** special timestwo operation for time values in histogram setup */
523b6c3722Schristos static void
timestwo(struct timeval * v)533b6c3722Schristos timestwo(struct timeval* v)
543b6c3722Schristos {
553b6c3722Schristos #ifndef S_SPLINT_S
563b6c3722Schristos if(v->tv_sec == 0 && v->tv_usec == 0) {
573b6c3722Schristos v->tv_usec = 1;
583b6c3722Schristos return;
593b6c3722Schristos }
603b6c3722Schristos v->tv_sec *= 2;
613b6c3722Schristos v->tv_usec *= 2;
623b6c3722Schristos if(v->tv_usec == 1024*1024) {
633b6c3722Schristos /* nice values and easy to compute */
643b6c3722Schristos v->tv_sec = 1;
653b6c3722Schristos v->tv_usec = 0;
663b6c3722Schristos }
673b6c3722Schristos #endif
683b6c3722Schristos }
693b6c3722Schristos
703b6c3722Schristos /** do setup exponentially */
713b6c3722Schristos static void
dosetup(struct timehist * hist)723b6c3722Schristos dosetup(struct timehist* hist)
733b6c3722Schristos {
743b6c3722Schristos struct timeval last;
753b6c3722Schristos size_t i;
763b6c3722Schristos memset(&last, 0, sizeof(last));
773b6c3722Schristos for(i=0; i<hist->num; i++) {
783b6c3722Schristos hist->buckets[i].lower = last;
793b6c3722Schristos timestwo(&last);
803b6c3722Schristos hist->buckets[i].upper = last;
813b6c3722Schristos hist->buckets[i].count = 0;
823b6c3722Schristos }
833b6c3722Schristos }
843b6c3722Schristos
timehist_setup(void)853b6c3722Schristos struct timehist* timehist_setup(void)
863b6c3722Schristos {
873b6c3722Schristos struct timehist* hist = (struct timehist*)calloc(1,
883b6c3722Schristos sizeof(struct timehist));
893b6c3722Schristos if(!hist)
903b6c3722Schristos return NULL;
913b6c3722Schristos hist->num = NUM_BUCKETS_HIST;
923b6c3722Schristos hist->buckets = (struct th_buck*)calloc(hist->num,
933b6c3722Schristos sizeof(struct th_buck));
943b6c3722Schristos if(!hist->buckets) {
953b6c3722Schristos free(hist);
963b6c3722Schristos return NULL;
973b6c3722Schristos }
983b6c3722Schristos /* setup the buckets */
993b6c3722Schristos dosetup(hist);
1003b6c3722Schristos return hist;
1013b6c3722Schristos }
1023b6c3722Schristos
timehist_delete(struct timehist * hist)1033b6c3722Schristos void timehist_delete(struct timehist* hist)
1043b6c3722Schristos {
1053b6c3722Schristos if(!hist)
1063b6c3722Schristos return;
1073b6c3722Schristos free(hist->buckets);
1083b6c3722Schristos free(hist);
1093b6c3722Schristos }
1103b6c3722Schristos
timehist_clear(struct timehist * hist)1113b6c3722Schristos void timehist_clear(struct timehist* hist)
1123b6c3722Schristos {
1133b6c3722Schristos size_t i;
1143b6c3722Schristos for(i=0; i<hist->num; i++)
1153b6c3722Schristos hist->buckets[i].count = 0;
1163b6c3722Schristos }
1173b6c3722Schristos
timehist_insert(struct timehist * hist,struct timeval * tv)1183b6c3722Schristos void timehist_insert(struct timehist* hist, struct timeval* tv)
1193b6c3722Schristos {
1203b6c3722Schristos size_t i;
1213b6c3722Schristos for(i=0; i<hist->num; i++) {
1223b6c3722Schristos if(timeval_smaller(tv, &hist->buckets[i].upper)) {
1233b6c3722Schristos hist->buckets[i].count++;
1243b6c3722Schristos return;
1253b6c3722Schristos }
1263b6c3722Schristos }
1273b6c3722Schristos /* dump in last bucket */
1283b6c3722Schristos hist->buckets[hist->num-1].count++;
1293b6c3722Schristos }
1303b6c3722Schristos
timehist_print(struct timehist * hist)1313b6c3722Schristos void timehist_print(struct timehist* hist)
1323b6c3722Schristos {
1333b6c3722Schristos #ifndef S_SPLINT_S
1343b6c3722Schristos size_t i;
1353b6c3722Schristos for(i=0; i<hist->num; i++) {
1363b6c3722Schristos if(hist->buckets[i].count != 0) {
1373b6c3722Schristos printf("%4d.%6.6d %4d.%6.6d %u\n",
1383b6c3722Schristos (int)hist->buckets[i].lower.tv_sec,
1393b6c3722Schristos (int)hist->buckets[i].lower.tv_usec,
1403b6c3722Schristos (int)hist->buckets[i].upper.tv_sec,
1413b6c3722Schristos (int)hist->buckets[i].upper.tv_usec,
1423b6c3722Schristos (unsigned)hist->buckets[i].count);
1433b6c3722Schristos }
1443b6c3722Schristos }
1453b6c3722Schristos #endif
1463b6c3722Schristos }
1473b6c3722Schristos
timehist_log(struct timehist * hist,const char * name)1483b6c3722Schristos void timehist_log(struct timehist* hist, const char* name)
1493b6c3722Schristos {
1503b6c3722Schristos #ifndef S_SPLINT_S
1513b6c3722Schristos size_t i;
1523b6c3722Schristos log_info("[25%%]=%g median[50%%]=%g [75%%]=%g",
1533b6c3722Schristos timehist_quartile(hist, 0.25),
1543b6c3722Schristos timehist_quartile(hist, 0.50),
1553b6c3722Schristos timehist_quartile(hist, 0.75));
1563b6c3722Schristos /* 0000.000000 0000.000000 0 */
1573b6c3722Schristos log_info("lower(secs) upper(secs) %s", name);
1583b6c3722Schristos for(i=0; i<hist->num; i++) {
1593b6c3722Schristos if(hist->buckets[i].count != 0) {
1603b6c3722Schristos log_info("%4d.%6.6d %4d.%6.6d %u",
1613b6c3722Schristos (int)hist->buckets[i].lower.tv_sec,
1623b6c3722Schristos (int)hist->buckets[i].lower.tv_usec,
1633b6c3722Schristos (int)hist->buckets[i].upper.tv_sec,
1643b6c3722Schristos (int)hist->buckets[i].upper.tv_usec,
1653b6c3722Schristos (unsigned)hist->buckets[i].count);
1663b6c3722Schristos }
1673b6c3722Schristos }
1683b6c3722Schristos #endif
1693b6c3722Schristos }
1703b6c3722Schristos
1713b6c3722Schristos /** total number in histogram */
1723b6c3722Schristos static size_t
timehist_count(struct timehist * hist)1733b6c3722Schristos timehist_count(struct timehist* hist)
1743b6c3722Schristos {
1753b6c3722Schristos size_t i, res = 0;
1763b6c3722Schristos for(i=0; i<hist->num; i++)
1773b6c3722Schristos res += hist->buckets[i].count;
1783b6c3722Schristos return res;
1793b6c3722Schristos }
1803b6c3722Schristos
1813b6c3722Schristos double
timehist_quartile(struct timehist * hist,double q)1823b6c3722Schristos timehist_quartile(struct timehist* hist, double q)
1833b6c3722Schristos {
1843b6c3722Schristos double lookfor, passed, res;
1853b6c3722Schristos double low = 0, up = 0;
1863b6c3722Schristos size_t i;
1873b6c3722Schristos if(!hist || hist->num == 0)
1883b6c3722Schristos return 0.;
1893b6c3722Schristos /* look for i'th element, interpolated */
1903b6c3722Schristos lookfor = (double)timehist_count(hist);
1913b6c3722Schristos if(lookfor < 4)
1923b6c3722Schristos return 0.; /* not enough elements for a good estimate */
1933b6c3722Schristos lookfor *= q;
1943b6c3722Schristos passed = 0;
1953b6c3722Schristos i = 0;
1963b6c3722Schristos while(i+1 < hist->num &&
1973b6c3722Schristos passed+(double)hist->buckets[i].count < lookfor) {
1983b6c3722Schristos passed += (double)hist->buckets[i++].count;
1993b6c3722Schristos }
2003b6c3722Schristos /* got the right bucket */
2013b6c3722Schristos #ifndef S_SPLINT_S
2023b6c3722Schristos low = (double)hist->buckets[i].lower.tv_sec +
2033b6c3722Schristos (double)hist->buckets[i].lower.tv_usec/1000000.;
2043b6c3722Schristos up = (double)hist->buckets[i].upper.tv_sec +
2053b6c3722Schristos (double)hist->buckets[i].upper.tv_usec/1000000.;
2063b6c3722Schristos #endif
2073b6c3722Schristos res = (lookfor - passed)*(up-low)/((double)hist->buckets[i].count);
2083b6c3722Schristos return low+res;
2093b6c3722Schristos }
2103b6c3722Schristos
2113b6c3722Schristos void
timehist_export(struct timehist * hist,long long * array,size_t sz)2120cd9f4ecSchristos timehist_export(struct timehist* hist, long long* array, size_t sz)
2133b6c3722Schristos {
2143b6c3722Schristos size_t i;
2153b6c3722Schristos if(!hist) return;
2163b6c3722Schristos if(sz > hist->num)
2173b6c3722Schristos sz = hist->num;
2183b6c3722Schristos for(i=0; i<sz; i++)
2190cd9f4ecSchristos array[i] = (long long)hist->buckets[i].count;
2203b6c3722Schristos }
2213b6c3722Schristos
2223b6c3722Schristos void
timehist_import(struct timehist * hist,long long * array,size_t sz)2230cd9f4ecSchristos timehist_import(struct timehist* hist, long long* array, size_t sz)
2243b6c3722Schristos {
2253b6c3722Schristos size_t i;
2263b6c3722Schristos if(!hist) return;
2273b6c3722Schristos if(sz > hist->num)
2283b6c3722Schristos sz = hist->num;
2293b6c3722Schristos for(i=0; i<sz; i++)
2300cd9f4ecSchristos hist->buckets[i].count = (size_t)array[i];
2313b6c3722Schristos }
232