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