throughput.c revision 49434
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 * 2649434Sbrian * $Id: throughput.c,v 1.9 1999/05/08 11:07:47 brian Exp $ 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 4331272Sbrianvoid 4449434Sbrianthroughput_init(struct pppThroughput *t, int period) 4531272Sbrian{ 4631272Sbrian t->OctetsIn = t->OctetsOut = 0; 4749434Sbrian t->SamplePeriod = period; 4849434Sbrian t->SampleOctets = (long long *)calloc(period, sizeof *t->SampleOctets); 4949434Sbrian t->OctetsPerSecond = t->BestOctetsPerSecond = 0; 5049434Sbrian t->nSample = 0; 5149434Sbrian time(&t->BestOctetsPerSecondTime); 5236285Sbrian memset(&t->Timer, '\0', sizeof t->Timer); 5336285Sbrian t->Timer.name = "throughput"; 5436285Sbrian t->uptime = 0; 5549434Sbrian t->downtime = 0; 5636285Sbrian t->rolling = 0; 5749434Sbrian t->callback.data = NULL; 5849434Sbrian t->callback.fn = NULL; 5931272Sbrian throughput_stop(t); 6031272Sbrian} 6131272Sbrian 6231272Sbrianvoid 6349434Sbrianthroughput_destroy(struct pppThroughput *t) 6449434Sbrian{ 6549434Sbrian if (t && t->SampleOctets) { 6649434Sbrian throughput_stop(t); 6749434Sbrian free(t->SampleOctets); 6849434Sbrian t->SampleOctets = 0; 6949434Sbrian } 7049434Sbrian} 7149434Sbrian 7249434Sbrianint 7349434Sbrianthroughput_uptime(struct pppThroughput *t) 7449434Sbrian{ 7549434Sbrian time_t downat; 7649434Sbrian 7749434Sbrian downat = t->downtime ? t->downtime : time(NULL); 7849434Sbrian return t->uptime ? downat - t->uptime : 0; 7949434Sbrian} 8049434Sbrian 8149434Sbrianvoid 8236285Sbrianthroughput_disp(struct pppThroughput *t, struct prompt *prompt) 8331272Sbrian{ 8449434Sbrian int secs_up, divisor; 8531272Sbrian 8649434Sbrian secs_up = throughput_uptime(t); 8749434Sbrian prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 8849434Sbrian (secs_up / 60) % 60, secs_up % 60); 8949434Sbrian if (t->downtime) 9049434Sbrian prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 9149434Sbrian else 9249434Sbrian prompt_Printf(prompt, "\n"); 9349434Sbrian 9449434Sbrian divisor = secs_up ? secs_up : 1; 9546686Sbrian prompt_Printf(prompt, "%qu octets in, %qu octets out\n", 9636285Sbrian t->OctetsIn, t->OctetsOut); 9736285Sbrian if (t->rolling) { 9846686Sbrian prompt_Printf(prompt, " overall %6qu bytes/sec\n", 9949434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 10049434Sbrian prompt_Printf(prompt, " %s %6qu bytes/sec (over the last" 10149434Sbrian " %d secs)\n", t->downtime ? "average " : "currently", 10249434Sbrian t->OctetsPerSecond, 10349434Sbrian secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 10446686Sbrian prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 10536819Sbrian t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 10631272Sbrian } else 10746686Sbrian prompt_Printf(prompt, "Overall %qu bytes/sec\n", 10849434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 10931272Sbrian} 11031272Sbrian 11131272Sbrian 11231272Sbrianvoid 11331272Sbrianthroughput_log(struct pppThroughput *t, int level, const char *title) 11431272Sbrian{ 11531272Sbrian if (t->uptime) { 11631272Sbrian int secs_up; 11731272Sbrian 11849434Sbrian secs_up = throughput_uptime(t); 11931272Sbrian if (title) 12046686Sbrian log_Printf(level, "%s: Connect time: %d secs: %qu octets in, %qu octets" 12131272Sbrian " out\n", title, secs_up, t->OctetsIn, t->OctetsOut); 12231272Sbrian else 12349434Sbrian log_Printf(level, "Connect time: %d secs: %qu octets in," 12449434Sbrian " %qu octets out\n", secs_up, t->OctetsIn, t->OctetsOut); 12531272Sbrian if (secs_up == 0) 12631272Sbrian secs_up = 1; 12736285Sbrian if (t->rolling) 12846686Sbrian log_Printf(level, " total %qu bytes/sec, peak %qu bytes/sec on %s", 12949434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 13049434Sbrian ctime(&t->BestOctetsPerSecondTime)); 13131272Sbrian else 13246686Sbrian log_Printf(level, " total %qu bytes/sec\n", 13349434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up); 13431272Sbrian } 13531272Sbrian} 13631272Sbrian 13731272Sbrianstatic void 13831343Sbrianthroughput_sampler(void *v) 13931272Sbrian{ 14031343Sbrian struct pppThroughput *t = (struct pppThroughput *)v; 14146686Sbrian unsigned long long old; 14249434Sbrian int uptime, divisor; 14331272Sbrian 14436285Sbrian timer_Stop(&t->Timer); 14531272Sbrian 14649434Sbrian uptime = throughput_uptime(t); 14749434Sbrian divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 14831272Sbrian old = t->SampleOctets[t->nSample]; 14931272Sbrian t->SampleOctets[t->nSample] = t->OctetsIn + t->OctetsOut; 15049434Sbrian t->OctetsPerSecond = (t->SampleOctets[t->nSample] - old) / divisor; 15136819Sbrian if (t->BestOctetsPerSecond < t->OctetsPerSecond) { 15231272Sbrian t->BestOctetsPerSecond = t->OctetsPerSecond; 15349434Sbrian time(&t->BestOctetsPerSecondTime); 15436819Sbrian } 15549434Sbrian if (++t->nSample == t->SamplePeriod) 15631272Sbrian t->nSample = 0; 15731272Sbrian 15849434Sbrian if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 15949434Sbrian (*t->callback.fn)(t->callback.data); 16049434Sbrian 16136285Sbrian timer_Start(&t->Timer); 16231272Sbrian} 16331272Sbrian 16431272Sbrianvoid 16536285Sbrianthroughput_start(struct pppThroughput *t, const char *name, int rolling) 16631272Sbrian{ 16749434Sbrian int i; 16836285Sbrian timer_Stop(&t->Timer); 16949434Sbrian 17049434Sbrian for (i = 0; i < t->SamplePeriod; i++) 17149434Sbrian t->SampleOctets[i] = 0; 17249434Sbrian t->nSample = 0; 17349434Sbrian t->OctetsIn = t->OctetsOut = 0; 17449434Sbrian t->OctetsPerSecond = t->BestOctetsPerSecond = 0; 17549434Sbrian time(&t->BestOctetsPerSecondTime); 17649434Sbrian t->downtime = 0; 17749434Sbrian time(&t->uptime); 17849434Sbrian throughput_restart(t, name, rolling); 17949434Sbrian} 18049434Sbrian 18149434Sbrianvoid 18249434Sbrianthroughput_restart(struct pppThroughput *t, const char *name, int rolling) 18349434Sbrian{ 18449434Sbrian timer_Stop(&t->Timer); 18536285Sbrian t->rolling = rolling ? 1 : 0; 18636285Sbrian if (t->rolling) { 18731272Sbrian t->Timer.load = SECTICKS; 18831272Sbrian t->Timer.func = throughput_sampler; 18936285Sbrian t->Timer.name = name; 19031272Sbrian t->Timer.arg = t; 19136285Sbrian timer_Start(&t->Timer); 19249434Sbrian } else { 19349434Sbrian t->Timer.load = 0; 19449434Sbrian t->Timer.func = NULL; 19549434Sbrian t->Timer.name = NULL; 19649434Sbrian t->Timer.arg = NULL; 19731272Sbrian } 19831272Sbrian} 19931272Sbrian 20031272Sbrianvoid 20131272Sbrianthroughput_stop(struct pppThroughput *t) 20231272Sbrian{ 20349434Sbrian if (t->Timer.state != TIMER_STOPPED) 20449434Sbrian time(&t->downtime); 20536285Sbrian timer_Stop(&t->Timer); 20631272Sbrian} 20731272Sbrian 20831272Sbrianvoid 20946686Sbrianthroughput_addin(struct pppThroughput *t, long long n) 21031272Sbrian{ 21131272Sbrian t->OctetsIn += n; 21231272Sbrian} 21331272Sbrian 21431272Sbrianvoid 21546686Sbrianthroughput_addout(struct pppThroughput *t, long long n) 21631272Sbrian{ 21731272Sbrian t->OctetsOut += n; 21831272Sbrian} 21936934Sbrian 22036934Sbrianvoid 22136934Sbrianthroughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 22236934Sbrian{ 22336934Sbrian if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 22436934Sbrian int i; 22536934Sbrian 22649434Sbrian for (i = 0; i < t->SamplePeriod; i++) 22736934Sbrian t->SampleOctets[i] = 0; 22836934Sbrian t->nSample = 0; 22936934Sbrian } 23036934Sbrian 23136934Sbrian if (clear_type & THROUGHPUT_OVERALL) { 23249434Sbrian int divisor; 23336934Sbrian 23449434Sbrian if ((divisor = throughput_uptime(t)) == 0) 23549434Sbrian divisor = 1; 23646686Sbrian prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 23749434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 23836934Sbrian t->OctetsIn = t->OctetsOut = 0; 23949434Sbrian t->downtime = 0; 24049434Sbrian time(&t->uptime); 24136934Sbrian } 24236934Sbrian 24336934Sbrian if (clear_type & THROUGHPUT_CURRENT) { 24446686Sbrian prompt_Printf(prompt, "current cleared (was %6qu bytes/sec)\n", 24536934Sbrian t->OctetsPerSecond); 24636934Sbrian t->OctetsPerSecond = 0; 24736934Sbrian } 24836934Sbrian 24936934Sbrian if (clear_type & THROUGHPUT_PEAK) { 25036934Sbrian char *time_buf, *last; 25136934Sbrian 25236934Sbrian time_buf = ctime(&t->BestOctetsPerSecondTime); 25336934Sbrian last = time_buf + strlen(time_buf); 25436934Sbrian if (last > time_buf && *--last == '\n') 25536934Sbrian *last = '\0'; 25646686Sbrian prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 25749434Sbrian t->BestOctetsPerSecond, time_buf); 25836934Sbrian t->BestOctetsPerSecond = 0; 25949434Sbrian time(&t->BestOctetsPerSecondTime); 26036934Sbrian } 26136934Sbrian} 26249434Sbrian 26349434Sbrianvoid 26449434Sbrianthroughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 26549434Sbrian{ 26649434Sbrian t->callback.fn = fn; 26749434Sbrian t->callback.data = data; 26849434Sbrian} 269