From: Wouter Wijngaards Date: Wed, 27 Jun 2007 14:59:44 +0000 (+0000) Subject: Histogram X-Git-Tag: release-0.4~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6907d9a9898bab699d22f2a08247225db3efbbe7;p=thirdparty%2Funbound.git Histogram git-svn-id: file:///svn/unbound/trunk@428 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/doc/Changelog b/doc/Changelog index 854de32c7..815356c70 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -7,6 +7,7 @@ This means that unbound tried the host for retries up to 120 secs. The rto value will time out after host-ttl seconds from the cache. This keeps such unresolvable queries from taking up resources. + - utility for keeping histogram. 26 June 2007: Wouter - mesh is called by worker, and iterator uses it. diff --git a/services/mesh.c b/services/mesh.c index c643c63fd..ba99b5c79 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -50,6 +50,7 @@ #include "util/module.h" #include "util/region-allocator.h" #include "util/data/msgencode.h" +#include "util/timehist.h" /** compare two mesh_states */ static int @@ -89,6 +90,12 @@ mesh_create(int num_modules, struct module_func_block** modfunc, log_err("mesh area alloc: out of memory"); return NULL; } + mesh->histogram = timehist_setup(); + if(!mesh->histogram) { + free(mesh); + log_err("mesh area alloc: out of memory"); + return NULL; + } mesh->num_modules = num_modules; mesh->modfunc = modfunc; mesh->env = env; @@ -115,6 +122,7 @@ mesh_delete(struct mesh_area* mesh) return; /* free all query states */ traverse_postorder(&mesh->all, &mesh_delete_helper, NULL); + timehist_delete(mesh->histogram); free(mesh); } @@ -444,6 +452,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, (int)duration.tv_sec, (int)duration.tv_usec); m->s.env->mesh->replies_sent++; timeval_add(&m->s.env->mesh->replies_sum_wait, &duration); + timehist_insert(m->s.env->mesh->histogram, &duration); } } @@ -543,13 +552,14 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate, (void)rbtree_delete(&mesh->run, mstate); } else mstate = NULL; } - mesh_stats(mesh, "mesh_run: end"); + if(verbosity >= VERB_ALGO) + mesh_stats(mesh, "mesh_run: end"); } void mesh_stats(struct mesh_area* mesh, const char* str) { - verbose(VERB_ALGO, "%s %u states (%u with reply, %u detached), " + log_info("%s %u states (%u with reply, %u detached), " "%u waiting replies", str, (unsigned)mesh->all.count, (unsigned)mesh->num_reply_states, (unsigned)mesh->num_detached_states, @@ -558,8 +568,10 @@ mesh_stats(struct mesh_area* mesh, const char* str) struct timeval avg; timeval_divide(&avg, &mesh->replies_sum_wait, mesh->replies_sent); - verbose(VERB_ALGO, "sent %u replies, with average wait " + log_info("sent %u replies, with average wait " "of %d.%6.6d sec", (unsigned)mesh->replies_sent, (int)avg.tv_sec, (int)avg.tv_usec); + log_info("histogram of reply wait times"); + timehist_log(mesh->histogram); } } diff --git a/services/mesh.h b/services/mesh.h index 67803d6b6..bf6a863e0 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -55,6 +55,7 @@ struct mesh_reply; struct query_info; struct reply_info; struct outbound_entry; +struct timehist; /** * Mesh of query states @@ -87,6 +88,8 @@ struct mesh_area { size_t replies_sent; /** sum of waiting times for the replies */ struct timeval replies_sum_wait; + /** histogram of time values */ + struct timehist* histogram; }; /** diff --git a/util/timehist.c b/util/timehist.c new file mode 100644 index 000000000..6d9f95199 --- /dev/null +++ b/util/timehist.c @@ -0,0 +1,169 @@ +/* + * util/timehist.c - make histogram of time values. + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains functions to make a histogram of time values. + */ +#include "config.h" +#include "util/timehist.h" +#include "util/log.h" + +/** special timestwo operation for time values in histogram setup */ +static void +timestwo(struct timeval* v) +{ +#ifndef S_SPLINT_S + if(v->tv_sec == 0 && v->tv_usec == 0) { + v->tv_usec = 1; + return; + } + v->tv_sec *= 2; + v->tv_usec *= 2; + if(v->tv_usec == 1024*1024) { + /* nice values and easy to compute */ + v->tv_sec = 1; + v->tv_usec = 0; + } +#endif +} + +/** do setup exponentially */ +static void +dosetup(struct timehist* hist) +{ + struct timeval last; + size_t i; + memset(&last, 0, sizeof(last)); + for(i=0; inum; i++) { + hist->buckets[i].lower = last; + timestwo(&last); + hist->buckets[i].upper = last; + hist->buckets[i].count = 0; + } +} + +struct timehist* timehist_setup() +{ + struct timehist* hist = (struct timehist*)calloc(1, + sizeof(struct timehist)); + if(!hist) + return NULL; + hist->num = 40; + hist->buckets = (struct th_buck*)calloc(hist->num, + sizeof(struct th_buck)); + if(!hist->buckets) { + free(hist); + return NULL; + } + /* setup the buckets */ + dosetup(hist); + return hist; +} + +void timehist_delete(struct timehist* hist) +{ + if(!hist) + return; + free(hist->buckets); + free(hist); +} + +/** histogram compare of time values */ +static int +timeval_smaller(struct timeval* x, struct timeval* y) +{ +#ifndef S_SPLINT_S + if(x->tv_sec < y->tv_sec) + return 1; + else if(x->tv_sec == y->tv_sec) { + if(x->tv_usec <= y->tv_usec) + return 1; + else return 0; + } + else return 0; +#endif +} + + +void timehist_insert(struct timehist* hist, struct timeval* tv) +{ + size_t i; + for(i=0; inum; i++) { + if(timeval_smaller(tv, &hist->buckets[i].upper)) { + hist->buckets[i].count++; + return; + } + } + /* dump in last bucket */ + hist->buckets[hist->num-1].count++; +} + +void timehist_print(struct timehist* hist) +{ +#ifndef S_SPLINT_S + size_t i; + for(i=0; inum; i++) { + if(hist->buckets[i].count != 0) { + printf("%4d.%6.6d %4d.%6.6d %u\n", + (int)hist->buckets[i].lower.tv_sec, + (int)hist->buckets[i].lower.tv_usec, + (int)hist->buckets[i].upper.tv_sec, + (int)hist->buckets[i].upper.tv_usec, + (unsigned)hist->buckets[i].count); + } + } +#endif +} + +void timehist_log(struct timehist* hist) +{ +#ifndef S_SPLINT_S + size_t i; + /* 0000.000000 0000.000000 0 */ + log_info("lower(secs) upper(secs) replycount"); + for(i=0; inum; i++) { + if(hist->buckets[i].count != 0) { + log_info("%4d.%6.6d %4d.%6.6d %u", + (int)hist->buckets[i].lower.tv_sec, + (int)hist->buckets[i].lower.tv_usec, + (int)hist->buckets[i].upper.tv_sec, + (int)hist->buckets[i].upper.tv_usec, + (unsigned)hist->buckets[i].count); + } + } +#endif +} diff --git a/util/timehist.h b/util/timehist.h new file mode 100644 index 000000000..3dbeb607f --- /dev/null +++ b/util/timehist.h @@ -0,0 +1,98 @@ +/* + * util/timehist.h - make histogram of time values. + * + * Copyright (c) 2007, NLnet Labs. All rights reserved. + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NLNET LABS nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * + * This file contains functions to make a histogram of time values. + */ + +#ifndef UTIL_TIMEHIST_H +#define UTIL_TIMEHIST_H + +/** + * Bucket of time history information + */ +struct th_buck { + /** lower bound */ + struct timeval lower; + /** upper bound */ + struct timeval upper; + /** number of items */ + size_t count; +}; + +/** + * Keep histogram of time values. + */ +struct timehist { + /** number of buckets */ + size_t num; + /** bucket array */ + struct th_buck* buckets; +}; + +/** + * Setup a histogram, default + * @return histogram or NULL on malloc failure. + */ +struct timehist* timehist_setup(); + +/** + * Delete histogram + * @param hist: to delete + */ +void timehist_delete(struct timehist* hist); + +/** + * Add time value to histogram. + * @param hist: histogram + * @param tv: time value + */ +void timehist_insert(struct timehist* hist, struct timeval* tv); + +/** + * Printout histogram + * @param hist: histogram + */ +void timehist_print(struct timehist* hist); + +/** + * Log histogram, print it to the logfile. + * @param hist: histogram + */ +void timehist_log(struct timehist* hist); + +#endif /* UTIL_TIMEHIST_H */