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