throughput.c revision 64670
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 64670 2000-08-15 10:25:42Z 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{ 4731272Sbrian t->OctetsIn = t->OctetsOut = 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 ! */ 8849447Sbrian int i; 8949447Sbrian 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); 11436285Sbrian if (t->rolling) { 11546686Sbrian prompt_Printf(prompt, " overall %6qu bytes/sec\n", 11649434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 11764670Sbrian prompt_Printf(prompt, " %s %6qu bytes/sec in, %6qu bytes/sec out " 11864670Sbrian "(over the last %d secs)\n", 11964670Sbrian t->downtime ? "average " : "currently", 12064670Sbrian t->in.OctetsPerSecond, t->out.OctetsPerSecond, 12149434Sbrian secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 12246686Sbrian prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 12336819Sbrian t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 12431272Sbrian } else 12549582Sbrian prompt_Printf(prompt, "Overall %llu bytes/sec\n", 12649434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 12731272Sbrian} 12831272Sbrian 12931272Sbrian 13031272Sbrianvoid 13131272Sbrianthroughput_log(struct pppThroughput *t, int level, const char *title) 13231272Sbrian{ 13331272Sbrian if (t->uptime) { 13431272Sbrian int secs_up; 13531272Sbrian 13649434Sbrian secs_up = throughput_uptime(t); 13764670Sbrian if (title == NULL) 13864670Sbrian title = ""; 13964670Sbrian log_Printf(level, "%s%sConnect time: %d secs: %llu octets in, %llu octets" 14064670Sbrian " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn, 14164670Sbrian t->OctetsOut); 14231272Sbrian if (secs_up == 0) 14331272Sbrian secs_up = 1; 14436285Sbrian if (t->rolling) 14549582Sbrian log_Printf(level, " total %llu bytes/sec, peak %llu bytes/sec on %s", 14649434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 14749434Sbrian ctime(&t->BestOctetsPerSecondTime)); 14831272Sbrian else 14949582Sbrian log_Printf(level, " total %llu bytes/sec\n", 15049434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up); 15131272Sbrian } 15231272Sbrian} 15331272Sbrian 15431272Sbrianstatic void 15531343Sbrianthroughput_sampler(void *v) 15631272Sbrian{ 15731343Sbrian struct pppThroughput *t = (struct pppThroughput *)v; 15846686Sbrian unsigned long long old; 15949434Sbrian int uptime, divisor; 16064670Sbrian unsigned long long octets; 16131272Sbrian 16236285Sbrian timer_Stop(&t->Timer); 16331272Sbrian 16449434Sbrian uptime = throughput_uptime(t); 16549434Sbrian divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 16664670Sbrian 16764670Sbrian old = t->in.SampleOctets[t->nSample]; 16864670Sbrian t->in.SampleOctets[t->nSample] = t->OctetsIn; 16964670Sbrian t->in.OctetsPerSecond = (t->in.SampleOctets[t->nSample] - old) / divisor; 17064670Sbrian 17164670Sbrian old = t->out.SampleOctets[t->nSample]; 17264670Sbrian t->out.SampleOctets[t->nSample] = t->OctetsOut; 17364670Sbrian t->out.OctetsPerSecond = (t->out.SampleOctets[t->nSample] - old) / divisor; 17464670Sbrian 17564670Sbrian octets = t->in.OctetsPerSecond + t->out.OctetsPerSecond; 17664670Sbrian if (t->BestOctetsPerSecond < octets) { 17764670Sbrian t->BestOctetsPerSecond = octets; 17849434Sbrian time(&t->BestOctetsPerSecondTime); 17936819Sbrian } 18064670Sbrian 18149434Sbrian if (++t->nSample == t->SamplePeriod) 18231272Sbrian t->nSample = 0; 18331272Sbrian 18449434Sbrian if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 18549434Sbrian (*t->callback.fn)(t->callback.data); 18649434Sbrian 18736285Sbrian timer_Start(&t->Timer); 18831272Sbrian} 18931272Sbrian 19031272Sbrianvoid 19136285Sbrianthroughput_start(struct pppThroughput *t, const char *name, int rolling) 19231272Sbrian{ 19349434Sbrian int i; 19436285Sbrian timer_Stop(&t->Timer); 19549434Sbrian 19649434Sbrian for (i = 0; i < t->SamplePeriod; i++) 19764670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 19849434Sbrian t->nSample = 0; 19949434Sbrian t->OctetsIn = t->OctetsOut = 0; 20064670Sbrian t->in.OctetsPerSecond = t->out.OctetsPerSecond = t->BestOctetsPerSecond = 0; 20149434Sbrian time(&t->BestOctetsPerSecondTime); 20249434Sbrian t->downtime = 0; 20349434Sbrian time(&t->uptime); 20449434Sbrian throughput_restart(t, name, rolling); 20549434Sbrian} 20649434Sbrian 20749434Sbrianvoid 20849434Sbrianthroughput_restart(struct pppThroughput *t, const char *name, int rolling) 20949434Sbrian{ 21049434Sbrian timer_Stop(&t->Timer); 21136285Sbrian t->rolling = rolling ? 1 : 0; 21236285Sbrian if (t->rolling) { 21331272Sbrian t->Timer.load = SECTICKS; 21431272Sbrian t->Timer.func = throughput_sampler; 21536285Sbrian t->Timer.name = name; 21631272Sbrian t->Timer.arg = t; 21736285Sbrian timer_Start(&t->Timer); 21849434Sbrian } else { 21949434Sbrian t->Timer.load = 0; 22049434Sbrian t->Timer.func = NULL; 22149434Sbrian t->Timer.name = NULL; 22249434Sbrian t->Timer.arg = NULL; 22331272Sbrian } 22431272Sbrian} 22531272Sbrian 22631272Sbrianvoid 22731272Sbrianthroughput_stop(struct pppThroughput *t) 22831272Sbrian{ 22949434Sbrian if (t->Timer.state != TIMER_STOPPED) 23049434Sbrian time(&t->downtime); 23136285Sbrian timer_Stop(&t->Timer); 23231272Sbrian} 23331272Sbrian 23431272Sbrianvoid 23546686Sbrianthroughput_addin(struct pppThroughput *t, long long n) 23631272Sbrian{ 23731272Sbrian t->OctetsIn += n; 23831272Sbrian} 23931272Sbrian 24031272Sbrianvoid 24146686Sbrianthroughput_addout(struct pppThroughput *t, long long n) 24231272Sbrian{ 24331272Sbrian t->OctetsOut += n; 24431272Sbrian} 24536934Sbrian 24636934Sbrianvoid 24736934Sbrianthroughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 24836934Sbrian{ 24936934Sbrian if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 25036934Sbrian int i; 25136934Sbrian 25249434Sbrian for (i = 0; i < t->SamplePeriod; i++) 25364670Sbrian t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 25436934Sbrian t->nSample = 0; 25536934Sbrian } 25636934Sbrian 25736934Sbrian if (clear_type & THROUGHPUT_OVERALL) { 25849434Sbrian int divisor; 25936934Sbrian 26049434Sbrian if ((divisor = throughput_uptime(t)) == 0) 26149434Sbrian divisor = 1; 26246686Sbrian prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 26349434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 26436934Sbrian t->OctetsIn = t->OctetsOut = 0; 26549434Sbrian t->downtime = 0; 26649434Sbrian time(&t->uptime); 26736934Sbrian } 26836934Sbrian 26936934Sbrian if (clear_type & THROUGHPUT_CURRENT) { 27064670Sbrian prompt_Printf(prompt, "current cleared (was %6qu bytes/sec in," 27164670Sbrian " %6qu bytes/sec out)\n", 27264670Sbrian t->in.OctetsPerSecond, t->out.OctetsPerSecond); 27364670Sbrian t->in.OctetsPerSecond = t->out.OctetsPerSecond = 0; 27436934Sbrian } 27536934Sbrian 27636934Sbrian if (clear_type & THROUGHPUT_PEAK) { 27736934Sbrian char *time_buf, *last; 27836934Sbrian 27936934Sbrian time_buf = ctime(&t->BestOctetsPerSecondTime); 28036934Sbrian last = time_buf + strlen(time_buf); 28136934Sbrian if (last > time_buf && *--last == '\n') 28236934Sbrian *last = '\0'; 28346686Sbrian prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 28449434Sbrian t->BestOctetsPerSecond, time_buf); 28536934Sbrian t->BestOctetsPerSecond = 0; 28649434Sbrian time(&t->BestOctetsPerSecondTime); 28736934Sbrian } 28836934Sbrian} 28949434Sbrian 29049434Sbrianvoid 29149434Sbrianthroughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 29249434Sbrian{ 29349434Sbrian t->callback.fn = fn; 29449434Sbrian t->callback.data = data; 29549434Sbrian} 296