2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/usr.sbin/ppp/throughput.c,v 1.13.2.3 2002/09/01 02:12:32 brian Exp $
27 * $DragonFly: src/usr.sbin/ppp/throughput.c,v 1.3 2008/05/19 10:19:49 corecode Exp $
30 #include <sys/types.h>
31 #include <sys/select.h>
42 #include "throughput.h"
43 #include "descriptor.h"
48 throughput_init(struct pppThroughput
*t
, int period
)
50 t
->OctetsIn
= t
->OctetsOut
= t
->PacketsIn
= t
->PacketsOut
= 0;
51 t
->SamplePeriod
= period
;
52 t
->in
.SampleOctets
= (long long *)
53 calloc(period
, sizeof *t
->in
.SampleOctets
);
54 t
->in
.OctetsPerSecond
= 0;
55 t
->out
.SampleOctets
= (long long *)
56 calloc(period
, sizeof *t
->out
.SampleOctets
);
57 t
->out
.OctetsPerSecond
= 0;
58 t
->BestOctetsPerSecond
= 0;
60 time(&t
->BestOctetsPerSecondTime
);
61 memset(&t
->Timer
, '\0', sizeof t
->Timer
);
62 t
->Timer
.name
= "throughput";
66 t
->callback
.data
= NULL
;
67 t
->callback
.fn
= NULL
;
72 throughput_destroy(struct pppThroughput
*t
)
74 if (t
&& t
->in
.SampleOctets
) {
76 free(t
->in
.SampleOctets
);
77 free(t
->out
.SampleOctets
);
78 t
->in
.SampleOctets
= NULL
;
79 t
->out
.SampleOctets
= NULL
;
84 throughput_uptime(struct pppThroughput
*t
)
88 downat
= t
->downtime
? t
->downtime
: time(NULL
);
89 if (t
->uptime
&& downat
< t
->uptime
) {
90 /* Euch ! The clock's gone back ! */
93 for (i
= 0; i
< t
->SamplePeriod
; i
++)
94 t
->in
.SampleOctets
[i
] = t
->out
.SampleOctets
[i
] = 0;
98 return t
->uptime
? downat
- t
->uptime
: 0;
102 throughput_disp(struct pppThroughput
*t
, struct prompt
*prompt
)
104 int secs_up
, divisor
;
106 secs_up
= throughput_uptime(t
);
107 prompt_Printf(prompt
, "Connect time: %d:%02d:%02d", secs_up
/ 3600,
108 (secs_up
/ 60) % 60, secs_up
% 60);
110 prompt_Printf(prompt
, " - down at %s", ctime(&t
->downtime
));
112 prompt_Printf(prompt
, "\n");
114 divisor
= secs_up
? secs_up
: 1;
115 prompt_Printf(prompt
, "%llu octets in, %llu octets out\n",
116 t
->OctetsIn
, t
->OctetsOut
);
117 prompt_Printf(prompt
, "%llu packets in, %llu packets out\n",
118 t
->PacketsIn
, t
->PacketsOut
);
120 prompt_Printf(prompt
, " overall %6qu bytes/sec\n",
121 (t
->OctetsIn
+ t
->OctetsOut
) / divisor
);
122 prompt_Printf(prompt
, " %s %6qu bytes/sec in, %6qu bytes/sec out "
123 "(over the last %d secs)\n",
124 t
->downtime
? "average " : "currently",
125 t
->in
.OctetsPerSecond
, t
->out
.OctetsPerSecond
,
126 secs_up
> t
->SamplePeriod
? t
->SamplePeriod
: secs_up
);
127 prompt_Printf(prompt
, " peak %6qu bytes/sec on %s",
128 t
->BestOctetsPerSecond
, ctime(&t
->BestOctetsPerSecondTime
));
130 prompt_Printf(prompt
, "Overall %llu bytes/sec\n",
131 (t
->OctetsIn
+ t
->OctetsOut
) / divisor
);
136 throughput_log(struct pppThroughput
*t
, int level
, const char *title
)
141 secs_up
= throughput_uptime(t
);
144 log_Printf(level
, "%s%sConnect time: %d secs: %llu octets in, %llu octets"
145 " out\n", title
, *title
? ": " : "", secs_up
, t
->OctetsIn
,
147 log_Printf(level
, "%s%s%llu packets in, %llu packets out\n",
148 title
, *title
? ": " : "", t
->PacketsIn
, t
->PacketsOut
);
152 log_Printf(level
, " total %llu bytes/sec, peak %llu bytes/sec on %s",
153 (t
->OctetsIn
+ t
->OctetsOut
) / secs_up
, t
->BestOctetsPerSecond
,
154 ctime(&t
->BestOctetsPerSecondTime
));
156 log_Printf(level
, " total %llu bytes/sec\n",
157 (t
->OctetsIn
+ t
->OctetsOut
) / secs_up
);
162 throughput_sampler(void *v
)
164 struct pppThroughput
*t
= (struct pppThroughput
*)v
;
165 unsigned long long old
;
167 unsigned long long octets
;
169 timer_Stop(&t
->Timer
);
171 uptime
= throughput_uptime(t
);
172 divisor
= uptime
< t
->SamplePeriod
? uptime
+ 1 : t
->SamplePeriod
;
174 old
= t
->in
.SampleOctets
[t
->nSample
];
175 t
->in
.SampleOctets
[t
->nSample
] = t
->OctetsIn
;
176 t
->in
.OctetsPerSecond
= (t
->in
.SampleOctets
[t
->nSample
] - old
) / divisor
;
178 old
= t
->out
.SampleOctets
[t
->nSample
];
179 t
->out
.SampleOctets
[t
->nSample
] = t
->OctetsOut
;
180 t
->out
.OctetsPerSecond
= (t
->out
.SampleOctets
[t
->nSample
] - old
) / divisor
;
182 octets
= t
->in
.OctetsPerSecond
+ t
->out
.OctetsPerSecond
;
183 if (t
->BestOctetsPerSecond
< octets
) {
184 t
->BestOctetsPerSecond
= octets
;
185 time(&t
->BestOctetsPerSecondTime
);
188 if (++t
->nSample
== t
->SamplePeriod
)
191 if (t
->callback
.fn
!= NULL
&& uptime
>= t
->SamplePeriod
)
192 (*t
->callback
.fn
)(t
->callback
.data
);
194 timer_Start(&t
->Timer
);
198 throughput_start(struct pppThroughput
*t
, const char *name
, int rolling
)
201 timer_Stop(&t
->Timer
);
203 for (i
= 0; i
< t
->SamplePeriod
; i
++)
204 t
->in
.SampleOctets
[i
] = t
->out
.SampleOctets
[i
] = 0;
206 t
->OctetsIn
= t
->OctetsOut
= 0;
207 t
->in
.OctetsPerSecond
= t
->out
.OctetsPerSecond
= t
->BestOctetsPerSecond
= 0;
208 time(&t
->BestOctetsPerSecondTime
);
211 throughput_restart(t
, name
, rolling
);
215 throughput_restart(struct pppThroughput
*t
, const char *name
, int rolling
)
217 timer_Stop(&t
->Timer
);
218 t
->rolling
= rolling
? 1 : 0;
220 t
->Timer
.load
= SECTICKS
;
221 t
->Timer
.func
= throughput_sampler
;
222 t
->Timer
.name
= name
;
224 timer_Start(&t
->Timer
);
227 t
->Timer
.func
= NULL
;
228 t
->Timer
.name
= NULL
;
234 throughput_stop(struct pppThroughput
*t
)
236 if (t
->Timer
.state
!= TIMER_STOPPED
)
238 timer_Stop(&t
->Timer
);
242 throughput_addin(struct pppThroughput
*t
, long long n
)
249 throughput_addout(struct pppThroughput
*t
, long long n
)
256 throughput_clear(struct pppThroughput
*t
, int clear_type
, struct prompt
*prompt
)
258 if (clear_type
& (THROUGHPUT_OVERALL
|THROUGHPUT_CURRENT
)) {
261 for (i
= 0; i
< t
->SamplePeriod
; i
++)
262 t
->in
.SampleOctets
[i
] = t
->out
.SampleOctets
[i
] = 0;
266 if (clear_type
& THROUGHPUT_OVERALL
) {
269 if ((divisor
= throughput_uptime(t
)) == 0)
271 prompt_Printf(prompt
, "overall cleared (was %6qu bytes/sec)\n",
272 (t
->OctetsIn
+ t
->OctetsOut
) / divisor
);
273 t
->OctetsIn
= t
->OctetsOut
= 0;
278 if (clear_type
& THROUGHPUT_CURRENT
) {
279 prompt_Printf(prompt
, "current cleared (was %6qu bytes/sec in,"
280 " %6qu bytes/sec out)\n",
281 t
->in
.OctetsPerSecond
, t
->out
.OctetsPerSecond
);
282 t
->in
.OctetsPerSecond
= t
->out
.OctetsPerSecond
= 0;
285 if (clear_type
& THROUGHPUT_PEAK
) {
286 char *time_buf
, *last
;
288 time_buf
= ctime(&t
->BestOctetsPerSecondTime
);
289 last
= time_buf
+ strlen(time_buf
);
290 if (last
> time_buf
&& *--last
== '\n')
292 prompt_Printf(prompt
, "peak cleared (was %6qu bytes/sec on %s)\n",
293 t
->BestOctetsPerSecond
, time_buf
);
294 t
->BestOctetsPerSecond
= 0;
295 time(&t
->BestOctetsPerSecondTime
);
300 throughput_callback(struct pppThroughput
*t
, void (*fn
)(void *), void *data
)
303 t
->callback
.data
= data
;