throughput.c revision 98243
131921Sbrian/*- 231921Sbrian * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 331921Sbrian * All rights reserved. 431921Sbrian * 531921Sbrian * Redistribution and use in source and binary forms, with or without 631921Sbrian * modification, are permitted provided that the following conditions 731921Sbrian * are met: 831921Sbrian * 1. Redistributions of source code must retain the above copyright 931921Sbrian * notice, this list of conditions and the following disclaimer. 1031921Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1131921Sbrian * notice, this list of conditions and the following disclaimer in the 1231921Sbrian * documentation and/or other materials provided with the distribution. 1331921Sbrian * 1431921Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1531921Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1631921Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1731921Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1831921Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1931921Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2031921Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2131921Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2231921Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2331921Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2431921Sbrian * SUCH DAMAGE. 2531921Sbrian * 2650479Speter * $FreeBSD: head/usr.sbin/ppp/throughput.c 98243 2002-06-15 08:03:30Z brian $ 2731272Sbrian */ 2831272Sbrian 2936285Sbrian#include <sys/types.h> 3031272Sbrian 3131272Sbrian#include <stdio.h> 3249434Sbrian#include <stdlib.h> 3336285Sbrian#include <string.h> 3436285Sbrian#include <termios.h> 3531272Sbrian#include <time.h> 3631272Sbrian 3731343Sbrian#include "log.h" 3831272Sbrian#include "timer.h" 3931272Sbrian#include "throughput.h" 4036285Sbrian#include "descriptor.h" 4136285Sbrian#include "prompt.h" 4231272Sbrian 4364670Sbrian 4431272Sbrianvoid 4549434Sbrianthroughput_init(struct pppThroughput *t, int period) 4631272Sbrian{ 4765178Sbrian t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 4849434Sbrian t->SamplePeriod = period; 4964670Sbrian t->in.SampleOctets = (long long *) 5064670Sbrian calloc(period, sizeof *t->in.SampleOctets); 5164670Sbrian t->in.OctetsPerSecond = 0; 5264670Sbrian t->out.SampleOctets = (long long *) 5364670Sbrian calloc(period, sizeof *t->out.SampleOctets); 5464670Sbrian t->out.OctetsPerSecond = 0; 5564670Sbrian t->BestOctetsPerSecond = 0; 5649434Sbrian t->nSample = 0; 5749434Sbrian time(&t->BestOctetsPerSecondTime); 5836285Sbrian memset(&t->Timer, '\0', sizeof t->Timer); 5936285Sbrian t->Timer.name = "throughput"; 6036285Sbrian t->uptime = 0; 6149434Sbrian t->downtime = 0; 6236285Sbrian t->rolling = 0; 6349434Sbrian t->callback.data = NULL; 6449434Sbrian t->callback.fn = NULL; 6531272Sbrian throughput_stop(t); 6631272Sbrian} 6731272Sbrian 6831272Sbrianvoid 6949434Sbrianthroughput_destroy(struct pppThroughput *t) 7049434Sbrian{ 7164670Sbrian if (t && t->in.SampleOctets) { 7249434Sbrian throughput_stop(t); 7364670Sbrian free(t->in.SampleOctets); 7464670Sbrian free(t->out.SampleOctets); 7564670Sbrian t->in.SampleOctets = NULL; 7664670Sbrian t->out.SampleOctets = NULL; 7749434Sbrian } 7849434Sbrian} 7949434Sbrian 8049434Sbrianint 8149434Sbrianthroughput_uptime(struct pppThroughput *t) 8249434Sbrian{ 8349434Sbrian time_t downat; 8449434Sbrian 8549434Sbrian downat = t->downtime ? t->downtime : time(NULL); 8649447Sbrian if (t->uptime && downat < t->uptime) { 8749447Sbrian /* Euch ! The clock's gone back ! */ 8898243Sbrian int i; 8998243Sbrian 9049447Sbrian for (i = 0; i < t->SamplePeriod; i++) 9164670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 9249447Sbrian t->nSample = 0; 9349447Sbrian t->uptime = downat; 9449447Sbrian } 9549434Sbrian return t->uptime ? downat - t->uptime : 0; 9649434Sbrian} 9749434Sbrian 9849434Sbrianvoid 9936285Sbrianthroughput_disp(struct pppThroughput *t, struct prompt *prompt) 10031272Sbrian{ 10149434Sbrian int secs_up, divisor; 10231272Sbrian 10349434Sbrian secs_up = throughput_uptime(t); 10449434Sbrian prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 10549434Sbrian (secs_up / 60) % 60, secs_up % 60); 10649434Sbrian if (t->downtime) 10749434Sbrian prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 10849434Sbrian else 10949434Sbrian prompt_Printf(prompt, "\n"); 11049434Sbrian 11149434Sbrian divisor = secs_up ? secs_up : 1; 11249582Sbrian prompt_Printf(prompt, "%llu octets in, %llu octets out\n", 11336285Sbrian t->OctetsIn, t->OctetsOut); 11465178Sbrian prompt_Printf(prompt, "%llu packets in, %llu packets out\n", 11565178Sbrian t->PacketsIn, t->PacketsOut); 11636285Sbrian if (t->rolling) { 11746686Sbrian prompt_Printf(prompt, " overall %6qu bytes/sec\n", 11849434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 11964670Sbrian prompt_Printf(prompt, " %s %6qu bytes/sec in, %6qu bytes/sec out " 12064670Sbrian "(over the last %d secs)\n", 12164670Sbrian t->downtime ? "average " : "currently", 12264670Sbrian t->in.OctetsPerSecond, t->out.OctetsPerSecond, 12349434Sbrian secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 12446686Sbrian prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 12536819Sbrian t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 12631272Sbrian } else 12749582Sbrian prompt_Printf(prompt, "Overall %llu bytes/sec\n", 12849434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 12931272Sbrian} 13031272Sbrian 13131272Sbrian 13231272Sbrianvoid 13331272Sbrianthroughput_log(struct pppThroughput *t, int level, const char *title) 13431272Sbrian{ 13531272Sbrian if (t->uptime) { 13631272Sbrian int secs_up; 13731272Sbrian 13849434Sbrian secs_up = throughput_uptime(t); 13964670Sbrian if (title == NULL) 14064670Sbrian title = ""; 14164670Sbrian log_Printf(level, "%s%sConnect time: %d secs: %llu octets in, %llu octets" 14265178Sbrian " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn, 14365178Sbrian t->OctetsOut); 14494895Sbrian log_Printf(level, "%s%s%llu packets in, %llu packets out\n", 14565178Sbrian title, *title ? ": " : "", t->PacketsIn, t->PacketsOut); 14631272Sbrian if (secs_up == 0) 14731272Sbrian secs_up = 1; 14836285Sbrian if (t->rolling) 14949582Sbrian log_Printf(level, " total %llu bytes/sec, peak %llu bytes/sec on %s", 15049434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 15149434Sbrian ctime(&t->BestOctetsPerSecondTime)); 15231272Sbrian else 15349582Sbrian log_Printf(level, " total %llu bytes/sec\n", 15449434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up); 15531272Sbrian } 15631272Sbrian} 15731272Sbrian 15831272Sbrianstatic void 15931343Sbrianthroughput_sampler(void *v) 16031272Sbrian{ 16131343Sbrian struct pppThroughput *t = (struct pppThroughput *)v; 16246686Sbrian unsigned long long old; 16349434Sbrian int uptime, divisor; 16464670Sbrian unsigned long long octets; 16531272Sbrian 16636285Sbrian timer_Stop(&t->Timer); 16731272Sbrian 16849434Sbrian uptime = throughput_uptime(t); 16949434Sbrian divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 17064670Sbrian 17164670Sbrian old = t->in.SampleOctets[t->nSample]; 17264670Sbrian t->in.SampleOctets[t->nSample] = t->OctetsIn; 17364670Sbrian t->in.OctetsPerSecond = (t->in.SampleOctets[t->nSample] - old) / divisor; 17464670Sbrian 17564670Sbrian old = t->out.SampleOctets[t->nSample]; 17664670Sbrian t->out.SampleOctets[t->nSample] = t->OctetsOut; 17764670Sbrian t->out.OctetsPerSecond = (t->out.SampleOctets[t->nSample] - old) / divisor; 17864670Sbrian 17964670Sbrian octets = t->in.OctetsPerSecond + t->out.OctetsPerSecond; 18064670Sbrian if (t->BestOctetsPerSecond < octets) { 18164670Sbrian t->BestOctetsPerSecond = octets; 18249434Sbrian time(&t->BestOctetsPerSecondTime); 18336819Sbrian } 18464670Sbrian 18549434Sbrian if (++t->nSample == t->SamplePeriod) 18631272Sbrian t->nSample = 0; 18731272Sbrian 18849434Sbrian if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 18949434Sbrian (*t->callback.fn)(t->callback.data); 19049434Sbrian 19136285Sbrian timer_Start(&t->Timer); 19231272Sbrian} 19331272Sbrian 19431272Sbrianvoid 19536285Sbrianthroughput_start(struct pppThroughput *t, const char *name, int rolling) 19631272Sbrian{ 19749434Sbrian int i; 19836285Sbrian timer_Stop(&t->Timer); 19949434Sbrian 20049434Sbrian for (i = 0; i < t->SamplePeriod; i++) 20164670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 20249434Sbrian t->nSample = 0; 20349434Sbrian t->OctetsIn = t->OctetsOut = 0; 20464670Sbrian t->in.OctetsPerSecond = t->out.OctetsPerSecond = t->BestOctetsPerSecond = 0; 20549434Sbrian time(&t->BestOctetsPerSecondTime); 20649434Sbrian t->downtime = 0; 20749434Sbrian time(&t->uptime); 20849434Sbrian throughput_restart(t, name, rolling); 20949434Sbrian} 21049434Sbrian 21149434Sbrianvoid 21249434Sbrianthroughput_restart(struct pppThroughput *t, const char *name, int rolling) 21349434Sbrian{ 21449434Sbrian timer_Stop(&t->Timer); 21536285Sbrian t->rolling = rolling ? 1 : 0; 21636285Sbrian if (t->rolling) { 21731272Sbrian t->Timer.load = SECTICKS; 21831272Sbrian t->Timer.func = throughput_sampler; 21936285Sbrian t->Timer.name = name; 22031272Sbrian t->Timer.arg = t; 22136285Sbrian timer_Start(&t->Timer); 22249434Sbrian } else { 22349434Sbrian t->Timer.load = 0; 22449434Sbrian t->Timer.func = NULL; 22549434Sbrian t->Timer.name = NULL; 22649434Sbrian t->Timer.arg = NULL; 22731272Sbrian } 22831272Sbrian} 22931272Sbrian 23031272Sbrianvoid 23131272Sbrianthroughput_stop(struct pppThroughput *t) 23231272Sbrian{ 23349434Sbrian if (t->Timer.state != TIMER_STOPPED) 23449434Sbrian time(&t->downtime); 23536285Sbrian timer_Stop(&t->Timer); 23631272Sbrian} 23731272Sbrian 23831272Sbrianvoid 23946686Sbrianthroughput_addin(struct pppThroughput *t, long long n) 24031272Sbrian{ 24131272Sbrian t->OctetsIn += n; 24265178Sbrian t->PacketsIn++; 24331272Sbrian} 24431272Sbrian 24531272Sbrianvoid 24646686Sbrianthroughput_addout(struct pppThroughput *t, long long n) 24731272Sbrian{ 24831272Sbrian t->OctetsOut += n; 24965178Sbrian t->PacketsOut++; 25031272Sbrian} 25136934Sbrian 25236934Sbrianvoid 25336934Sbrianthroughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 25436934Sbrian{ 25536934Sbrian if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 25636934Sbrian int i; 25736934Sbrian 25849434Sbrian for (i = 0; i < t->SamplePeriod; i++) 25964670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 26036934Sbrian t->nSample = 0; 26136934Sbrian } 26236934Sbrian 26336934Sbrian if (clear_type & THROUGHPUT_OVERALL) { 26449434Sbrian int divisor; 26536934Sbrian 26649434Sbrian if ((divisor = throughput_uptime(t)) == 0) 26749434Sbrian divisor = 1; 26846686Sbrian prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 26949434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 27036934Sbrian t->OctetsIn = t->OctetsOut = 0; 27149434Sbrian t->downtime = 0; 27249434Sbrian time(&t->uptime); 27398243Sbrian } 27436934Sbrian 27536934Sbrian if (clear_type & THROUGHPUT_CURRENT) { 27664670Sbrian prompt_Printf(prompt, "current cleared (was %6qu bytes/sec in," 27764670Sbrian " %6qu bytes/sec out)\n", 27864670Sbrian t->in.OctetsPerSecond, t->out.OctetsPerSecond); 27964670Sbrian t->in.OctetsPerSecond = t->out.OctetsPerSecond = 0; 28036934Sbrian } 28136934Sbrian 28236934Sbrian if (clear_type & THROUGHPUT_PEAK) { 28336934Sbrian char *time_buf, *last; 28436934Sbrian 28536934Sbrian time_buf = ctime(&t->BestOctetsPerSecondTime); 28636934Sbrian last = time_buf + strlen(time_buf); 28736934Sbrian if (last > time_buf && *--last == '\n') 28836934Sbrian *last = '\0'; 28946686Sbrian prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 29098243Sbrian t->BestOctetsPerSecond, time_buf); 29136934Sbrian t->BestOctetsPerSecond = 0; 29249434Sbrian time(&t->BestOctetsPerSecondTime); 29336934Sbrian } 29436934Sbrian} 29549434Sbrian 29649434Sbrianvoid 29749434Sbrianthroughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 29849434Sbrian{ 29949434Sbrian t->callback.fn = fn; 30049434Sbrian t->callback.data = data; 30149434Sbrian} 302