xref: /netbsd-src/external/bsd/unbound/dist/util/timehist.c (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
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