bugfix with strerror_r - still not working but at least not using uninitialized data
[anytun.git] / src / openvpn / perf.c
blob3abf8c56f7548536ceac070d6cae713f9b02bf4f
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef WIN32
26 #include "config-win32.h"
27 #else
28 #include "config.h"
29 #endif
31 #include "syshead.h"
33 #include "perf.h"
35 #ifdef ENABLE_PERFORMANCE_METRICS
37 #include "error.h"
38 #include "otime.h"
40 #include "memdbg.h"
42 #ifdef USE_PTHREAD
43 #error ENABLE_PERFORMANCE_METRICS is incompatible with USE_PTHREAD
44 #endif
46 static const char *metric_names[] = {
47 "PERF_BIO_READ_PLAINTEXT",
48 "PERF_BIO_WRITE_PLAINTEXT",
49 "PERF_BIO_READ_CIPHERTEXT",
50 "PERF_BIO_WRITE_CIPHERTEXT",
51 "PERF_TLS_MULTI_PROCESS",
52 "PERF_IO_WAIT",
53 "PERF_EVENT_LOOP",
54 "PERF_MULTI_CREATE_INSTANCE",
55 "PERF_MULTI_CLOSE_INSTANCE",
56 "PERF_MULTI_SHOW_STATS",
57 "PERF_MULTI_BCAST",
58 "PERF_MULTI_MCAST",
59 "PERF_SCRIPT",
60 "PERF_READ_IN_LINK",
61 "PERF_PROC_IN_LINK",
62 "PERF_READ_IN_TUN",
63 "PERF_PROC_IN_TUN",
64 "PERF_PROC_OUT_LINK",
65 "PERF_PROC_OUT_TUN",
66 "PERF_PROC_OUT_TUN_MTCP"
69 struct perf
71 # define PS_INITIAL 0
72 # define PS_METER_RUNNING 1
73 # define PS_METER_INTERRUPTED 2
74 int state;
76 struct timeval start;
77 double sofar;
78 double sum;
79 double max;
80 double count;
83 struct perf_set
85 int stack_len;
86 int stack[STACK_N];
87 struct perf perf[PERF_N];
90 static struct perf_set perf_set;
92 static void perf_print_state (int lev);
94 static inline int
95 get_stack_index (int sdelta)
97 const int sindex = perf_set.stack_len + sdelta;
98 if (sindex >= 0 && sindex < STACK_N)
99 return sindex;
100 else
101 return -1;
104 static int
105 get_perf_index (int sdelta)
107 const int sindex = get_stack_index (sdelta);
108 if (sindex >= 0)
110 const int pindex = perf_set.stack[sindex];
111 if (pindex >= 0 && pindex < PERF_N)
112 return pindex;
113 else
114 return -1;
116 else
117 return -1;
120 static struct perf *
121 get_perf (int sdelta)
123 const int pindex = get_perf_index (sdelta);
124 if (pindex >= 0)
125 return &perf_set.perf[pindex];
126 else
127 return NULL;
130 static void
131 push_perf_index (int pindex)
133 const int sindex = get_stack_index (0);
134 const int newlen = get_stack_index (1);
135 if (sindex >= 0 && newlen >= 0
136 && pindex >= 0 && pindex < PERF_N)
138 int i;
139 for (i = 0; i < sindex; ++i)
140 if (perf_set.stack[i] == pindex)
142 perf_print_state (M_INFO);
143 msg (M_FATAL, "PERF: push_perf_index %s failed",
144 metric_names [pindex]);
147 perf_set.stack[sindex] = pindex;
148 perf_set.stack_len = newlen;
150 else
151 msg (M_FATAL, "PERF: push_perf_index: stack push error");
154 static void
155 pop_perf_index (void)
157 const int newlen = get_stack_index (-1);
158 if (newlen >= 0)
160 perf_set.stack_len = newlen;
162 else
163 msg (M_FATAL, "PERF: pop_perf_index: stack pop error");
166 static void
167 state_must_be (const struct perf *p, const int wanted)
169 if (p->state != wanted)
170 msg (M_FATAL, "PERF: bad state actual=%d wanted=%d",
171 p->state,
172 wanted);
175 static void
176 update_sofar (struct perf *p)
178 struct timeval current;
179 ASSERT (!gettimeofday (&current, NULL));
180 p->sofar += (double) tv_subtract (&current, &p->start, 600) / 1000000.0;
181 tv_clear (&p->start);
184 static void
185 perf_start (struct perf *p)
187 state_must_be (p, PS_INITIAL);
188 ASSERT (!gettimeofday (&p->start, NULL));
189 p->sofar = 0.0;
190 p->state = PS_METER_RUNNING;
193 static void
194 perf_stop (struct perf *p)
196 state_must_be (p, PS_METER_RUNNING);
197 update_sofar (p);
198 p->sum += p->sofar;
199 if (p->sofar > p->max)
200 p->max = p->sofar;
201 p->count += 1.0;
202 p->sofar = 0.0;
203 p->state = PS_INITIAL;
206 static void
207 perf_interrupt (struct perf *p)
209 state_must_be (p, PS_METER_RUNNING);
210 update_sofar (p);
211 p->state = PS_METER_INTERRUPTED;
214 static void
215 perf_resume (struct perf *p)
217 state_must_be (p, PS_METER_INTERRUPTED);
218 ASSERT (!gettimeofday (&p->start, NULL));
219 p->state = PS_METER_RUNNING;
222 void
223 perf_push (int type)
225 struct perf *prev;
226 struct perf *cur;
228 ASSERT (SIZE(metric_names) == PERF_N);
229 push_perf_index (type);
231 prev = get_perf (-2);
232 cur = get_perf (-1);
234 ASSERT (cur);
236 if (prev)
237 perf_interrupt (prev);
238 perf_start (cur);
241 void
242 perf_pop (void)
244 struct perf *prev;
245 struct perf *cur;
247 prev = get_perf (-2);
248 cur = get_perf (-1);
250 ASSERT (cur);
251 perf_stop (cur);
253 if (prev)
254 perf_resume (prev);
256 pop_perf_index ();
259 void
260 perf_output_results (void)
262 int i;
263 msg (M_INFO, "LATENCY PROFILE (mean and max are in milliseconds)");
264 for (i = 0; i < PERF_N; ++i)
266 struct perf *p = &perf_set.perf[i];
267 if (p->count > 0.0)
269 const double mean = p->sum / p->count;
270 msg (M_INFO, "%s n=%.0f mean=%.3f max=%.3f", metric_names[i], p->count, mean*1000.0, p->max*1000.0);
275 static void
276 perf_print_state (int lev)
278 struct gc_arena gc = gc_new ();
279 int i;
280 msg (lev, "PERF STATE");
281 msg (lev, "Stack:");
282 for (i = 0; i < perf_set.stack_len; ++i)
284 const int j = perf_set.stack[i];
285 const struct perf *p = &perf_set.perf[j];
286 msg (lev, "[%d] %s state=%d start=%s sofar=%f sum=%f max=%f count=%f",
288 metric_names[j],
289 p->state,
290 tv_string (&p->start, &gc),
291 p->sofar,
292 p->sum,
293 p->max,
294 p->count);
296 gc_free (&gc);
299 #else
300 static void dummy(void) {}
301 #endif