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