xref: /openbsd/sbin/unwind/libunbound/util/timehist.c (revision d500c338)
1ae8c6e27Sflorian /*
2ae8c6e27Sflorian  * util/timehist.c - make histogram of time values.
3ae8c6e27Sflorian  *
4ae8c6e27Sflorian  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5ae8c6e27Sflorian  *
6ae8c6e27Sflorian  * This software is open source.
7ae8c6e27Sflorian  *
8ae8c6e27Sflorian  * Redistribution and use in source and binary forms, with or without
9ae8c6e27Sflorian  * modification, are permitted provided that the following conditions
10ae8c6e27Sflorian  * are met:
11ae8c6e27Sflorian  *
12ae8c6e27Sflorian  * Redistributions of source code must retain the above copyright notice,
13ae8c6e27Sflorian  * this list of conditions and the following disclaimer.
14ae8c6e27Sflorian  *
15ae8c6e27Sflorian  * Redistributions in binary form must reproduce the above copyright notice,
16ae8c6e27Sflorian  * this list of conditions and the following disclaimer in the documentation
17ae8c6e27Sflorian  * and/or other materials provided with the distribution.
18ae8c6e27Sflorian  *
19ae8c6e27Sflorian  * Neither the name of the NLNET LABS nor the names of its contributors may
20ae8c6e27Sflorian  * be used to endorse or promote products derived from this software without
21ae8c6e27Sflorian  * specific prior written permission.
22ae8c6e27Sflorian  *
23ae8c6e27Sflorian  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24ae8c6e27Sflorian  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25ae8c6e27Sflorian  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26ae8c6e27Sflorian  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27ae8c6e27Sflorian  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28ae8c6e27Sflorian  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29ae8c6e27Sflorian  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30ae8c6e27Sflorian  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31ae8c6e27Sflorian  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32ae8c6e27Sflorian  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33ae8c6e27Sflorian  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34ae8c6e27Sflorian  */
35ae8c6e27Sflorian 
36ae8c6e27Sflorian /**
37ae8c6e27Sflorian  * \file
38ae8c6e27Sflorian  *
39ae8c6e27Sflorian  * This file contains functions to make a histogram of time values.
40ae8c6e27Sflorian  */
41ae8c6e27Sflorian #include "config.h"
42ae8c6e27Sflorian #ifdef HAVE_TIME_H
43ae8c6e27Sflorian #include <time.h>
44ae8c6e27Sflorian #endif
45ae8c6e27Sflorian #include <sys/time.h>
46ae8c6e27Sflorian #include <sys/types.h>
47ae8c6e27Sflorian #include "util/timehist.h"
48ae8c6e27Sflorian #include "util/log.h"
49*d500c338Sflorian #include "util/timeval_func.h"
50ae8c6e27Sflorian 
51ae8c6e27Sflorian /** special timestwo operation for time values in histogram setup */
52ae8c6e27Sflorian static void
timestwo(struct timeval * v)53ae8c6e27Sflorian timestwo(struct timeval* v)
54ae8c6e27Sflorian {
55ae8c6e27Sflorian #ifndef S_SPLINT_S
56ae8c6e27Sflorian 	if(v->tv_sec == 0 && v->tv_usec == 0) {
57ae8c6e27Sflorian 		v->tv_usec = 1;
58ae8c6e27Sflorian 		return;
59ae8c6e27Sflorian 	}
60ae8c6e27Sflorian 	v->tv_sec *= 2;
61ae8c6e27Sflorian 	v->tv_usec *= 2;
62ae8c6e27Sflorian 	if(v->tv_usec == 1024*1024) {
63ae8c6e27Sflorian 		/* nice values and easy to compute */
64ae8c6e27Sflorian 		v->tv_sec = 1;
65ae8c6e27Sflorian 		v->tv_usec = 0;
66ae8c6e27Sflorian 	}
67ae8c6e27Sflorian #endif
68ae8c6e27Sflorian }
69ae8c6e27Sflorian 
70ae8c6e27Sflorian /** do setup exponentially */
71ae8c6e27Sflorian static void
dosetup(struct timehist * hist)72ae8c6e27Sflorian dosetup(struct timehist* hist)
73ae8c6e27Sflorian {
74ae8c6e27Sflorian 	struct timeval last;
75ae8c6e27Sflorian 	size_t i;
76ae8c6e27Sflorian 	memset(&last, 0, sizeof(last));
77ae8c6e27Sflorian 	for(i=0; i<hist->num; i++) {
78ae8c6e27Sflorian 		hist->buckets[i].lower = last;
79ae8c6e27Sflorian 		timestwo(&last);
80ae8c6e27Sflorian 		hist->buckets[i].upper = last;
81ae8c6e27Sflorian 		hist->buckets[i].count = 0;
82ae8c6e27Sflorian 	}
83ae8c6e27Sflorian }
84ae8c6e27Sflorian 
timehist_setup(void)85ae8c6e27Sflorian struct timehist* timehist_setup(void)
86ae8c6e27Sflorian {
87ae8c6e27Sflorian 	struct timehist* hist = (struct timehist*)calloc(1,
88ae8c6e27Sflorian 		sizeof(struct timehist));
89ae8c6e27Sflorian 	if(!hist)
90ae8c6e27Sflorian 		return NULL;
91ae8c6e27Sflorian 	hist->num = NUM_BUCKETS_HIST;
92ae8c6e27Sflorian 	hist->buckets = (struct th_buck*)calloc(hist->num,
93ae8c6e27Sflorian 		sizeof(struct th_buck));
94ae8c6e27Sflorian 	if(!hist->buckets) {
95ae8c6e27Sflorian 		free(hist);
96ae8c6e27Sflorian 		return NULL;
97ae8c6e27Sflorian 	}
98ae8c6e27Sflorian 	/* setup the buckets */
99ae8c6e27Sflorian 	dosetup(hist);
100ae8c6e27Sflorian 	return hist;
101ae8c6e27Sflorian }
102ae8c6e27Sflorian 
timehist_delete(struct timehist * hist)103ae8c6e27Sflorian void timehist_delete(struct timehist* hist)
104ae8c6e27Sflorian {
105ae8c6e27Sflorian 	if(!hist)
106ae8c6e27Sflorian 		return;
107ae8c6e27Sflorian 	free(hist->buckets);
108ae8c6e27Sflorian 	free(hist);
109ae8c6e27Sflorian }
110ae8c6e27Sflorian 
timehist_clear(struct timehist * hist)111ae8c6e27Sflorian void timehist_clear(struct timehist* hist)
112ae8c6e27Sflorian {
113ae8c6e27Sflorian 	size_t i;
114ae8c6e27Sflorian 	for(i=0; i<hist->num; i++)
115ae8c6e27Sflorian 		hist->buckets[i].count = 0;
116ae8c6e27Sflorian }
117ae8c6e27Sflorian 
timehist_insert(struct timehist * hist,struct timeval * tv)118ae8c6e27Sflorian void timehist_insert(struct timehist* hist, struct timeval* tv)
119ae8c6e27Sflorian {
120ae8c6e27Sflorian 	size_t i;
121ae8c6e27Sflorian 	for(i=0; i<hist->num; i++) {
122ae8c6e27Sflorian 		if(timeval_smaller(tv, &hist->buckets[i].upper)) {
123ae8c6e27Sflorian 			hist->buckets[i].count++;
124ae8c6e27Sflorian 			return;
125ae8c6e27Sflorian 		}
126ae8c6e27Sflorian 	}
127ae8c6e27Sflorian 	/* dump in last bucket */
128ae8c6e27Sflorian 	hist->buckets[hist->num-1].count++;
129ae8c6e27Sflorian }
130ae8c6e27Sflorian 
timehist_print(struct timehist * hist)131ae8c6e27Sflorian void timehist_print(struct timehist* hist)
132ae8c6e27Sflorian {
133ae8c6e27Sflorian #ifndef S_SPLINT_S
134ae8c6e27Sflorian 	size_t i;
135ae8c6e27Sflorian 	for(i=0; i<hist->num; i++) {
136ae8c6e27Sflorian 		if(hist->buckets[i].count != 0) {
137ae8c6e27Sflorian 			printf("%4d.%6.6d %4d.%6.6d %u\n",
138ae8c6e27Sflorian 				(int)hist->buckets[i].lower.tv_sec,
139ae8c6e27Sflorian 				(int)hist->buckets[i].lower.tv_usec,
140ae8c6e27Sflorian 				(int)hist->buckets[i].upper.tv_sec,
141ae8c6e27Sflorian 				(int)hist->buckets[i].upper.tv_usec,
142ae8c6e27Sflorian 				(unsigned)hist->buckets[i].count);
143ae8c6e27Sflorian 		}
144ae8c6e27Sflorian 	}
145ae8c6e27Sflorian #endif
146ae8c6e27Sflorian }
147ae8c6e27Sflorian 
timehist_log(struct timehist * hist,const char * name)148ae8c6e27Sflorian void timehist_log(struct timehist* hist, const char* name)
149ae8c6e27Sflorian {
150ae8c6e27Sflorian #ifndef S_SPLINT_S
151ae8c6e27Sflorian 	size_t i;
152ae8c6e27Sflorian 	log_info("[25%%]=%g median[50%%]=%g [75%%]=%g",
153ae8c6e27Sflorian 		timehist_quartile(hist, 0.25),
154ae8c6e27Sflorian 		timehist_quartile(hist, 0.50),
155ae8c6e27Sflorian 		timehist_quartile(hist, 0.75));
156ae8c6e27Sflorian 	/*        0000.000000 0000.000000 0 */
157ae8c6e27Sflorian 	log_info("lower(secs) upper(secs) %s", name);
158ae8c6e27Sflorian 	for(i=0; i<hist->num; i++) {
159ae8c6e27Sflorian 		if(hist->buckets[i].count != 0) {
160ae8c6e27Sflorian 			log_info("%4d.%6.6d %4d.%6.6d %u",
161ae8c6e27Sflorian 				(int)hist->buckets[i].lower.tv_sec,
162ae8c6e27Sflorian 				(int)hist->buckets[i].lower.tv_usec,
163ae8c6e27Sflorian 				(int)hist->buckets[i].upper.tv_sec,
164ae8c6e27Sflorian 				(int)hist->buckets[i].upper.tv_usec,
165ae8c6e27Sflorian 				(unsigned)hist->buckets[i].count);
166ae8c6e27Sflorian 		}
167ae8c6e27Sflorian 	}
168ae8c6e27Sflorian #endif
169ae8c6e27Sflorian }
170ae8c6e27Sflorian 
171ae8c6e27Sflorian /** total number in histogram */
172ae8c6e27Sflorian static size_t
timehist_count(struct timehist * hist)173ae8c6e27Sflorian timehist_count(struct timehist* hist)
174ae8c6e27Sflorian {
175ae8c6e27Sflorian 	size_t i, res = 0;
176ae8c6e27Sflorian 	for(i=0; i<hist->num; i++)
177ae8c6e27Sflorian 		res += hist->buckets[i].count;
178ae8c6e27Sflorian 	return res;
179ae8c6e27Sflorian }
180ae8c6e27Sflorian 
181ae8c6e27Sflorian double
timehist_quartile(struct timehist * hist,double q)182ae8c6e27Sflorian timehist_quartile(struct timehist* hist, double q)
183ae8c6e27Sflorian {
184ae8c6e27Sflorian 	double lookfor, passed, res;
185ae8c6e27Sflorian 	double low = 0, up = 0;
186ae8c6e27Sflorian 	size_t i;
187ae8c6e27Sflorian 	if(!hist || hist->num == 0)
188ae8c6e27Sflorian 		return 0.;
189ae8c6e27Sflorian 	/* look for i'th element, interpolated */
190ae8c6e27Sflorian 	lookfor = (double)timehist_count(hist);
191ae8c6e27Sflorian 	if(lookfor < 4)
192ae8c6e27Sflorian 		return 0.; /* not enough elements for a good estimate */
193ae8c6e27Sflorian 	lookfor *= q;
194ae8c6e27Sflorian 	passed = 0;
195ae8c6e27Sflorian 	i = 0;
196ae8c6e27Sflorian 	while(i+1 < hist->num &&
197ae8c6e27Sflorian 		passed+(double)hist->buckets[i].count < lookfor) {
198ae8c6e27Sflorian 		passed += (double)hist->buckets[i++].count;
199ae8c6e27Sflorian 	}
200ae8c6e27Sflorian 	/* got the right bucket */
201ae8c6e27Sflorian #ifndef S_SPLINT_S
202ae8c6e27Sflorian 	low = (double)hist->buckets[i].lower.tv_sec +
203ae8c6e27Sflorian 		(double)hist->buckets[i].lower.tv_usec/1000000.;
204ae8c6e27Sflorian 	up = (double)hist->buckets[i].upper.tv_sec +
205ae8c6e27Sflorian 		(double)hist->buckets[i].upper.tv_usec/1000000.;
206ae8c6e27Sflorian #endif
207ae8c6e27Sflorian 	res = (lookfor - passed)*(up-low)/((double)hist->buckets[i].count);
208ae8c6e27Sflorian 	return low+res;
209ae8c6e27Sflorian }
210ae8c6e27Sflorian 
211ae8c6e27Sflorian void
timehist_export(struct timehist * hist,long long * array,size_t sz)212ae8c6e27Sflorian timehist_export(struct timehist* hist, long long* array, size_t sz)
213ae8c6e27Sflorian {
214ae8c6e27Sflorian 	size_t i;
215ae8c6e27Sflorian 	if(!hist) return;
216ae8c6e27Sflorian 	if(sz > hist->num)
217ae8c6e27Sflorian 		sz = hist->num;
218ae8c6e27Sflorian 	for(i=0; i<sz; i++)
219ae8c6e27Sflorian 		array[i] = (long long)hist->buckets[i].count;
220ae8c6e27Sflorian }
221ae8c6e27Sflorian 
222ae8c6e27Sflorian void
timehist_import(struct timehist * hist,long long * array,size_t sz)223ae8c6e27Sflorian timehist_import(struct timehist* hist, long long* array, size_t sz)
224ae8c6e27Sflorian {
225ae8c6e27Sflorian 	size_t i;
226ae8c6e27Sflorian 	if(!hist) return;
227ae8c6e27Sflorian 	if(sz > hist->num)
228ae8c6e27Sflorian 		sz = hist->num;
229ae8c6e27Sflorian 	for(i=0; i<sz; i++)
230ae8c6e27Sflorian 		hist->buckets[i].count = (size_t)array[i];
231ae8c6e27Sflorian }
232