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