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
29 #include <sys/types.h>
40 #include "throughput.h"
41 #include "descriptor.h"
46 throughput_init(struct pppThroughput
*t
, int period
)
48 t
->OctetsIn
= t
->OctetsOut
= t
->PacketsIn
= t
->PacketsOut
= 0;
49 t
->SamplePeriod
= period
;
50 t
->in
.SampleOctets
= (long long *)
51 calloc(period
, sizeof *t
->in
.SampleOctets
);
52 t
->in
.OctetsPerSecond
= 0;
53 t
->out
.SampleOctets
= (long long *)
54 calloc(period
, sizeof *t
->out
.SampleOctets
);
55 t
->out
.OctetsPerSecond
= 0;
56 t
->BestOctetsPerSecond
= 0;
58 time(&t
->BestOctetsPerSecondTime
);
59 memset(&t
->Timer
, '\0', sizeof t
->Timer
);
60 t
->Timer
.name
= "throughput";
64 t
->callback
.data
= NULL
;
65 t
->callback
.fn
= NULL
;
70 throughput_destroy(struct pppThroughput
*t
)
72 if (t
&& t
->in
.SampleOctets
) {
74 free(t
->in
.SampleOctets
);
75 free(t
->out
.SampleOctets
);
76 t
->in
.SampleOctets
= NULL
;
77 t
->out
.SampleOctets
= NULL
;
82 throughput_uptime(struct pppThroughput
*t
)
86 downat
= t
->downtime
? t
->downtime
: time(NULL
);
87 if (t
->uptime
&& downat
< t
->uptime
) {
88 /* Euch ! The clock's gone back ! */
91 for (i
= 0; i
< t
->SamplePeriod
; i
++)
92 t
->in
.SampleOctets
[i
] = t
->out
.SampleOctets
[i
] = 0;
96 return t
->uptime
? downat
- t
->uptime
: 0;
100 throughput_disp(struct pppThroughput
*t
, struct prompt
*prompt
)
102 int secs_up
, divisor
;
104 secs_up
= throughput_uptime(t
);
105 prompt_Printf(prompt
, "Connect time: %d:%02d:%02d", secs_up
/ 3600,
106 (secs_up
/ 60) % 60, secs_up
% 60);
108 prompt_Printf(prompt
, " - down at %s", ctime(&t
->downtime
));
110 prompt_Printf(prompt
, "\n");
112 divisor
= secs_up
? secs_up
: 1;
113 prompt_Printf(prompt
, "%llu octets in, %llu octets out\n",
114 t
->OctetsIn
, t
->OctetsOut
);
115 prompt_Printf(prompt
, "%llu packets in, %llu packets out\n",
116 t
->PacketsIn
, t
->PacketsOut
);
118 prompt_Printf(prompt
, " overall %6llu bytes/sec\n",
119 (t
->OctetsIn
+ t
->OctetsOut
) / divisor
);
120 prompt_Printf(prompt
, " %s %6llu bytes/sec in, %6llu bytes/sec out "
121 "(over the last %d secs)\n",
122 t
->downtime
? "average " : "currently",
123 t
->in
.OctetsPerSecond
, t
->out
.OctetsPerSecond
,
124 secs_up
> t
->SamplePeriod
? t
->SamplePeriod
: secs_up
);
125 prompt_Printf(prompt
, " peak %6llu bytes/sec on %s",
126 t
->BestOctetsPerSecond
, ctime(&t
->BestOctetsPerSecondTime
));
128 prompt_Printf(prompt
, "Overall %llu bytes/sec\n",
129 (t
->OctetsIn
+ t
->OctetsOut
) / divisor
);
134 throughput_log(struct pppThroughput
*t
, int level
, const char *title
)
139 secs_up
= throughput_uptime(t
);
142 log_Printf(level
, "%s%sConnect time: %d secs: %llu octets in, %llu octets"
143 " out\n", title
, *title
? ": " : "", secs_up
, t
->OctetsIn
,
145 log_Printf(level
, "%s%s%llu packets in, %llu packets out\n",
146 title
, *title
? ": " : "", t
->PacketsIn
, t
->PacketsOut
);
150 log_Printf(level
, " total %llu bytes/sec, peak %llu bytes/sec on %s",
151 (t
->OctetsIn
+ t
->OctetsOut
) / secs_up
, t
->BestOctetsPerSecond
,
152 ctime(&t
->BestOctetsPerSecondTime
));
154 log_Printf(level
, " total %llu bytes/sec\n",
155 (t
->OctetsIn
+ t
->OctetsOut
) / secs_up
);
160 throughput_sampler(void *v
)
162 struct pppThroughput
*t
= (struct pppThroughput
*)v
;
163 unsigned long long old
;
165 unsigned long long octets
;
167 timer_Stop(&t
->Timer
);
169 uptime
= throughput_uptime(t
);
170 divisor
= uptime
< t
->SamplePeriod
? uptime
+ 1 : t
->SamplePeriod
;
172 old
= t
->in
.SampleOctets
[t
->nSample
];
173 t
->in
.SampleOctets
[t
->nSample
] = t
->OctetsIn
;
174 t
->in
.OctetsPerSecond
= (t
->in
.SampleOctets
[t
->nSample
] - old
) / divisor
;
176 old
= t
->out
.SampleOctets
[t
->nSample
];
177 t
->out
.SampleOctets
[t
->nSample
] = t
->OctetsOut
;
178 t
->out
.OctetsPerSecond
= (t
->out
.SampleOctets
[t
->nSample
] - old
) / divisor
;
180 octets
= t
->in
.OctetsPerSecond
+ t
->out
.OctetsPerSecond
;
181 if (t
->BestOctetsPerSecond
< octets
) {
182 t
->BestOctetsPerSecond
= octets
;
183 time(&t
->BestOctetsPerSecondTime
);
186 if (++t
->nSample
== t
->SamplePeriod
)
189 if (t
->callback
.fn
!= NULL
&& uptime
>= t
->SamplePeriod
)
190 (*t
->callback
.fn
)(t
->callback
.data
);
192 timer_Start(&t
->Timer
);
196 throughput_start(struct pppThroughput
*t
, const char *name
, int rolling
)
199 timer_Stop(&t
->Timer
);
201 for (i
= 0; i
< t
->SamplePeriod
; i
++)
202 t
->in
.SampleOctets
[i
] = t
->out
.SampleOctets
[i
] = 0;
204 t
->OctetsIn
= t
->OctetsOut
= t
->PacketsIn
= t
->PacketsOut
= 0;
205 t
->in
.OctetsPerSecond
= t
->out
.OctetsPerSecond
= t
->BestOctetsPerSecond
= 0;
206 time(&t
->BestOctetsPerSecondTime
);
209 throughput_restart(t
, name
, rolling
);
213 throughput_restart(struct pppThroughput
*t
, const char *name
, int rolling
)
215 timer_Stop(&t
->Timer
);
216 t
->rolling
= rolling
? 1 : 0;
218 t
->Timer
.load
= SECTICKS
;
219 t
->Timer
.func
= throughput_sampler
;
220 t
->Timer
.name
= name
;
222 timer_Start(&t
->Timer
);
225 t
->Timer
.func
= NULL
;
226 t
->Timer
.name
= NULL
;
232 throughput_stop(struct pppThroughput
*t
)
234 if (t
->Timer
.state
!= TIMER_STOPPED
)
236 timer_Stop(&t
->Timer
);
240 throughput_addin(struct pppThroughput
*t
, long long n
)
247 throughput_addout(struct pppThroughput
*t
, long long n
)
254 throughput_clear(struct pppThroughput
*t
, int clear_type
, struct prompt
*prompt
)
256 if (clear_type
& (THROUGHPUT_OVERALL
|THROUGHPUT_CURRENT
)) {
259 for (i
= 0; i
< t
->SamplePeriod
; i
++)
260 t
->in
.SampleOctets
[i
] = t
->out
.SampleOctets
[i
] = 0;
264 if (clear_type
& THROUGHPUT_OVERALL
) {
267 if ((divisor
= throughput_uptime(t
)) == 0)
269 prompt_Printf(prompt
, "overall cleared (was %6llu bytes/sec)\n",
270 (t
->OctetsIn
+ t
->OctetsOut
) / divisor
);
271 t
->OctetsIn
= t
->OctetsOut
= t
->PacketsIn
= t
->PacketsOut
= 0;
276 if (clear_type
& THROUGHPUT_CURRENT
) {
277 prompt_Printf(prompt
, "current cleared (was %6llu bytes/sec in,"
278 " %6llu bytes/sec out)\n",
279 t
->in
.OctetsPerSecond
, t
->out
.OctetsPerSecond
);
280 t
->in
.OctetsPerSecond
= t
->out
.OctetsPerSecond
= 0;
283 if (clear_type
& THROUGHPUT_PEAK
) {
284 char *time_buf
, *last
;
286 time_buf
= ctime(&t
->BestOctetsPerSecondTime
);
287 last
= time_buf
+ strlen(time_buf
);
288 if (last
> time_buf
&& *--last
== '\n')
290 prompt_Printf(prompt
, "peak cleared (was %6llu bytes/sec on %s)\n",
291 t
->BestOctetsPerSecond
, time_buf
);
292 t
->BestOctetsPerSecond
= 0;
293 time(&t
->BestOctetsPerSecondTime
);
298 throughput_callback(struct pppThroughput
*t
, void (*fn
)(void *), void *data
)
301 t
->callback
.data
= data
;