Coverage Report

Created: 2025-07-18 07:00

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