throughput.c revision 49447
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 * 2649447Sbrian * $Id: throughput.c,v 1.10 1999/08/05 10:32:15 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); 7849447Sbrian if (t->uptime && downat < t->uptime) { 7949447Sbrian /* Euch ! The clock's gone back ! */ 8049447Sbrian int i; 8149447Sbrian 8249447Sbrian for (i = 0; i < t->SamplePeriod; i++) 8349447Sbrian t->SampleOctets[i] = 0; 8449447Sbrian t->nSample = 0; 8549447Sbrian t->uptime = downat; 8649447Sbrian } 8749434Sbrian return t->uptime ? downat - t->uptime : 0; 8849434Sbrian} 8949434Sbrian 9049434Sbrianvoid 9136285Sbrianthroughput_disp(struct pppThroughput *t, struct prompt *prompt) 9231272Sbrian{ 9349434Sbrian int secs_up, divisor; 9431272Sbrian 9549434Sbrian secs_up = throughput_uptime(t); 9649434Sbrian prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 9749434Sbrian (secs_up / 60) % 60, secs_up % 60); 9849434Sbrian if (t->downtime) 9949434Sbrian prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 10049434Sbrian else 10149434Sbrian prompt_Printf(prompt, "\n"); 10249434Sbrian 10349434Sbrian divisor = secs_up ? secs_up : 1; 10446686Sbrian prompt_Printf(prompt, "%qu octets in, %qu octets out\n", 10536285Sbrian t->OctetsIn, t->OctetsOut); 10636285Sbrian if (t->rolling) { 10746686Sbrian prompt_Printf(prompt, " overall %6qu bytes/sec\n", 10849434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 10949434Sbrian prompt_Printf(prompt, " %s %6qu bytes/sec (over the last" 11049434Sbrian " %d secs)\n", t->downtime ? "average " : "currently", 11149434Sbrian t->OctetsPerSecond, 11249434Sbrian secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 11346686Sbrian prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 11436819Sbrian t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 11531272Sbrian } else 11646686Sbrian prompt_Printf(prompt, "Overall %qu bytes/sec\n", 11749434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 11831272Sbrian} 11931272Sbrian 12031272Sbrian 12131272Sbrianvoid 12231272Sbrianthroughput_log(struct pppThroughput *t, int level, const char *title) 12331272Sbrian{ 12431272Sbrian if (t->uptime) { 12531272Sbrian int secs_up; 12631272Sbrian 12749434Sbrian secs_up = throughput_uptime(t); 12831272Sbrian if (title) 12946686Sbrian log_Printf(level, "%s: Connect time: %d secs: %qu octets in, %qu octets" 13031272Sbrian " out\n", title, secs_up, t->OctetsIn, t->OctetsOut); 13131272Sbrian else 13249434Sbrian log_Printf(level, "Connect time: %d secs: %qu octets in," 13349434Sbrian " %qu octets out\n", secs_up, t->OctetsIn, t->OctetsOut); 13431272Sbrian if (secs_up == 0) 13531272Sbrian secs_up = 1; 13636285Sbrian if (t->rolling) 13746686Sbrian log_Printf(level, " total %qu bytes/sec, peak %qu bytes/sec on %s", 13849434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 13949434Sbrian ctime(&t->BestOctetsPerSecondTime)); 14031272Sbrian else 14146686Sbrian log_Printf(level, " total %qu bytes/sec\n", 14249434Sbrian (t->OctetsIn + t->OctetsOut) / secs_up); 14331272Sbrian } 14431272Sbrian} 14531272Sbrian 14631272Sbrianstatic void 14731343Sbrianthroughput_sampler(void *v) 14831272Sbrian{ 14931343Sbrian struct pppThroughput *t = (struct pppThroughput *)v; 15046686Sbrian unsigned long long old; 15149434Sbrian int uptime, divisor; 15231272Sbrian 15336285Sbrian timer_Stop(&t->Timer); 15431272Sbrian 15549434Sbrian uptime = throughput_uptime(t); 15649434Sbrian divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 15731272Sbrian old = t->SampleOctets[t->nSample]; 15831272Sbrian t->SampleOctets[t->nSample] = t->OctetsIn + t->OctetsOut; 15949434Sbrian t->OctetsPerSecond = (t->SampleOctets[t->nSample] - old) / divisor; 16036819Sbrian if (t->BestOctetsPerSecond < t->OctetsPerSecond) { 16131272Sbrian t->BestOctetsPerSecond = t->OctetsPerSecond; 16249434Sbrian time(&t->BestOctetsPerSecondTime); 16336819Sbrian } 16449434Sbrian if (++t->nSample == t->SamplePeriod) 16531272Sbrian t->nSample = 0; 16631272Sbrian 16749434Sbrian if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 16849434Sbrian (*t->callback.fn)(t->callback.data); 16949434Sbrian 17036285Sbrian timer_Start(&t->Timer); 17131272Sbrian} 17231272Sbrian 17331272Sbrianvoid 17436285Sbrianthroughput_start(struct pppThroughput *t, const char *name, int rolling) 17531272Sbrian{ 17649434Sbrian int i; 17736285Sbrian timer_Stop(&t->Timer); 17849434Sbrian 17949434Sbrian for (i = 0; i < t->SamplePeriod; i++) 18049434Sbrian t->SampleOctets[i] = 0; 18149434Sbrian t->nSample = 0; 18249434Sbrian t->OctetsIn = t->OctetsOut = 0; 18349434Sbrian t->OctetsPerSecond = t->BestOctetsPerSecond = 0; 18449434Sbrian time(&t->BestOctetsPerSecondTime); 18549434Sbrian t->downtime = 0; 18649434Sbrian time(&t->uptime); 18749434Sbrian throughput_restart(t, name, rolling); 18849434Sbrian} 18949434Sbrian 19049434Sbrianvoid 19149434Sbrianthroughput_restart(struct pppThroughput *t, const char *name, int rolling) 19249434Sbrian{ 19349434Sbrian timer_Stop(&t->Timer); 19436285Sbrian t->rolling = rolling ? 1 : 0; 19536285Sbrian if (t->rolling) { 19631272Sbrian t->Timer.load = SECTICKS; 19731272Sbrian t->Timer.func = throughput_sampler; 19836285Sbrian t->Timer.name = name; 19931272Sbrian t->Timer.arg = t; 20036285Sbrian timer_Start(&t->Timer); 20149434Sbrian } else { 20249434Sbrian t->Timer.load = 0; 20349434Sbrian t->Timer.func = NULL; 20449434Sbrian t->Timer.name = NULL; 20549434Sbrian t->Timer.arg = NULL; 20631272Sbrian } 20731272Sbrian} 20831272Sbrian 20931272Sbrianvoid 21031272Sbrianthroughput_stop(struct pppThroughput *t) 21131272Sbrian{ 21249434Sbrian if (t->Timer.state != TIMER_STOPPED) 21349434Sbrian time(&t->downtime); 21436285Sbrian timer_Stop(&t->Timer); 21531272Sbrian} 21631272Sbrian 21731272Sbrianvoid 21846686Sbrianthroughput_addin(struct pppThroughput *t, long long n) 21931272Sbrian{ 22031272Sbrian t->OctetsIn += n; 22131272Sbrian} 22231272Sbrian 22331272Sbrianvoid 22446686Sbrianthroughput_addout(struct pppThroughput *t, long long n) 22531272Sbrian{ 22631272Sbrian t->OctetsOut += n; 22731272Sbrian} 22836934Sbrian 22936934Sbrianvoid 23036934Sbrianthroughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 23136934Sbrian{ 23236934Sbrian if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 23336934Sbrian int i; 23436934Sbrian 23549434Sbrian for (i = 0; i < t->SamplePeriod; i++) 23636934Sbrian t->SampleOctets[i] = 0; 23736934Sbrian t->nSample = 0; 23836934Sbrian } 23936934Sbrian 24036934Sbrian if (clear_type & THROUGHPUT_OVERALL) { 24149434Sbrian int divisor; 24236934Sbrian 24349434Sbrian if ((divisor = throughput_uptime(t)) == 0) 24449434Sbrian divisor = 1; 24546686Sbrian prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 24649434Sbrian (t->OctetsIn + t->OctetsOut) / divisor); 24736934Sbrian t->OctetsIn = t->OctetsOut = 0; 24849434Sbrian t->downtime = 0; 24949434Sbrian time(&t->uptime); 25036934Sbrian } 25136934Sbrian 25236934Sbrian if (clear_type & THROUGHPUT_CURRENT) { 25346686Sbrian prompt_Printf(prompt, "current cleared (was %6qu bytes/sec)\n", 25436934Sbrian t->OctetsPerSecond); 25536934Sbrian t->OctetsPerSecond = 0; 25636934Sbrian } 25736934Sbrian 25836934Sbrian if (clear_type & THROUGHPUT_PEAK) { 25936934Sbrian char *time_buf, *last; 26036934Sbrian 26136934Sbrian time_buf = ctime(&t->BestOctetsPerSecondTime); 26236934Sbrian last = time_buf + strlen(time_buf); 26336934Sbrian if (last > time_buf && *--last == '\n') 26436934Sbrian *last = '\0'; 26546686Sbrian prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 26649434Sbrian t->BestOctetsPerSecond, time_buf); 26736934Sbrian t->BestOctetsPerSecond = 0; 26849434Sbrian time(&t->BestOctetsPerSecondTime); 26936934Sbrian } 27036934Sbrian} 27149434Sbrian 27249434Sbrianvoid 27349434Sbrianthroughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 27449434Sbrian{ 27549434Sbrian t->callback.fn = fn; 27649434Sbrian t->callback.data = data; 27749434Sbrian} 278