1c39934eaSBrian Somers /*- 2c39934eaSBrian Somers * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 3c39934eaSBrian Somers * All rights reserved. 4c39934eaSBrian Somers * 5c39934eaSBrian Somers * Redistribution and use in source and binary forms, with or without 6c39934eaSBrian Somers * modification, are permitted provided that the following conditions 7c39934eaSBrian Somers * are met: 8c39934eaSBrian Somers * 1. Redistributions of source code must retain the above copyright 9c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer. 10c39934eaSBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 11c39934eaSBrian Somers * notice, this list of conditions and the following disclaimer in the 12c39934eaSBrian Somers * documentation and/or other materials provided with the distribution. 13c39934eaSBrian Somers * 14c39934eaSBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c39934eaSBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c39934eaSBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c39934eaSBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c39934eaSBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c39934eaSBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c39934eaSBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c39934eaSBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c39934eaSBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c39934eaSBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c39934eaSBrian Somers * SUCH DAMAGE. 25c39934eaSBrian Somers * 26ab2de065SBrian Somers * $Id: throughput.c,v 1.9 1999/05/08 11:07:47 brian Exp $ 279a0b991fSBrian Somers */ 289a0b991fSBrian Somers 292764b86aSBrian Somers #include <sys/types.h> 309a0b991fSBrian Somers 319a0b991fSBrian Somers #include <stdio.h> 32ab2de065SBrian Somers #include <stdlib.h> 33e3c70ce9SBrian Somers #include <string.h> 3485b542cfSBrian Somers #include <termios.h> 359a0b991fSBrian Somers #include <time.h> 369a0b991fSBrian Somers 37b6e82f33SBrian Somers #include "log.h" 389a0b991fSBrian Somers #include "timer.h" 399a0b991fSBrian Somers #include "throughput.h" 4085b542cfSBrian Somers #include "descriptor.h" 4185b542cfSBrian Somers #include "prompt.h" 429a0b991fSBrian Somers 439a0b991fSBrian Somers void 44ab2de065SBrian Somers throughput_init(struct pppThroughput *t, int period) 459a0b991fSBrian Somers { 469a0b991fSBrian Somers t->OctetsIn = t->OctetsOut = 0; 47ab2de065SBrian Somers t->SamplePeriod = period; 48ab2de065SBrian Somers t->SampleOctets = (long long *)calloc(period, sizeof *t->SampleOctets); 49ab2de065SBrian Somers t->OctetsPerSecond = t->BestOctetsPerSecond = 0; 50ab2de065SBrian Somers t->nSample = 0; 51ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 52e3c70ce9SBrian Somers memset(&t->Timer, '\0', sizeof t->Timer); 533b0f8d2eSBrian Somers t->Timer.name = "throughput"; 54565e35e5SBrian Somers t->uptime = 0; 55ab2de065SBrian Somers t->downtime = 0; 561342caedSBrian Somers t->rolling = 0; 57ab2de065SBrian Somers t->callback.data = NULL; 58ab2de065SBrian Somers t->callback.fn = NULL; 599a0b991fSBrian Somers throughput_stop(t); 609a0b991fSBrian Somers } 619a0b991fSBrian Somers 629a0b991fSBrian Somers void 63ab2de065SBrian Somers throughput_destroy(struct pppThroughput *t) 64ab2de065SBrian Somers { 65ab2de065SBrian Somers if (t && t->SampleOctets) { 66ab2de065SBrian Somers throughput_stop(t); 67ab2de065SBrian Somers free(t->SampleOctets); 68ab2de065SBrian Somers t->SampleOctets = 0; 69ab2de065SBrian Somers } 70ab2de065SBrian Somers } 71ab2de065SBrian Somers 72ab2de065SBrian Somers int 73ab2de065SBrian Somers throughput_uptime(struct pppThroughput *t) 74ab2de065SBrian Somers { 75ab2de065SBrian Somers time_t downat; 76ab2de065SBrian Somers 77ab2de065SBrian Somers downat = t->downtime ? t->downtime : time(NULL); 78ab2de065SBrian Somers return t->uptime ? downat - t->uptime : 0; 79ab2de065SBrian Somers } 80ab2de065SBrian Somers 81ab2de065SBrian Somers void 82b6217683SBrian Somers throughput_disp(struct pppThroughput *t, struct prompt *prompt) 839a0b991fSBrian Somers { 84ab2de065SBrian Somers int secs_up, divisor; 859a0b991fSBrian Somers 86ab2de065SBrian Somers secs_up = throughput_uptime(t); 87ab2de065SBrian Somers prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 88ab2de065SBrian Somers (secs_up / 60) % 60, secs_up % 60); 89ab2de065SBrian Somers if (t->downtime) 90ab2de065SBrian Somers prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 91ab2de065SBrian Somers else 92ab2de065SBrian Somers prompt_Printf(prompt, "\n"); 93ab2de065SBrian Somers 94ab2de065SBrian Somers divisor = secs_up ? secs_up : 1; 955d9e6103SBrian Somers prompt_Printf(prompt, "%qu octets in, %qu octets out\n", 9685b542cfSBrian Somers t->OctetsIn, t->OctetsOut); 971342caedSBrian Somers if (t->rolling) { 985d9e6103SBrian Somers prompt_Printf(prompt, " overall %6qu bytes/sec\n", 99ab2de065SBrian Somers (t->OctetsIn + t->OctetsOut) / divisor); 100ab2de065SBrian Somers prompt_Printf(prompt, " %s %6qu bytes/sec (over the last" 101ab2de065SBrian Somers " %d secs)\n", t->downtime ? "average " : "currently", 102ab2de065SBrian Somers t->OctetsPerSecond, 103ab2de065SBrian Somers secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 1045d9e6103SBrian Somers prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 105255aa9e3SBrian Somers t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 1069a0b991fSBrian Somers } else 1075d9e6103SBrian Somers prompt_Printf(prompt, "Overall %qu bytes/sec\n", 108ab2de065SBrian Somers (t->OctetsIn + t->OctetsOut) / divisor); 1099a0b991fSBrian Somers } 1109a0b991fSBrian Somers 1119a0b991fSBrian Somers 1129a0b991fSBrian Somers void 1139a0b991fSBrian Somers throughput_log(struct pppThroughput *t, int level, const char *title) 1149a0b991fSBrian Somers { 1159a0b991fSBrian Somers if (t->uptime) { 1169a0b991fSBrian Somers int secs_up; 1179a0b991fSBrian Somers 118ab2de065SBrian Somers secs_up = throughput_uptime(t); 1199a0b991fSBrian Somers if (title) 1205d9e6103SBrian Somers log_Printf(level, "%s: Connect time: %d secs: %qu octets in, %qu octets" 1219a0b991fSBrian Somers " out\n", title, secs_up, t->OctetsIn, t->OctetsOut); 1229a0b991fSBrian Somers else 123ab2de065SBrian Somers log_Printf(level, "Connect time: %d secs: %qu octets in," 124ab2de065SBrian Somers " %qu octets out\n", secs_up, t->OctetsIn, t->OctetsOut); 1259a0b991fSBrian Somers if (secs_up == 0) 1269a0b991fSBrian Somers secs_up = 1; 1271342caedSBrian Somers if (t->rolling) 1285d9e6103SBrian Somers log_Printf(level, " total %qu bytes/sec, peak %qu bytes/sec on %s", 129255aa9e3SBrian Somers (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 130255aa9e3SBrian Somers ctime(&t->BestOctetsPerSecondTime)); 1319a0b991fSBrian Somers else 1325d9e6103SBrian Somers log_Printf(level, " total %qu bytes/sec\n", 1339a0b991fSBrian Somers (t->OctetsIn + t->OctetsOut) / secs_up); 1349a0b991fSBrian Somers } 1359a0b991fSBrian Somers } 1369a0b991fSBrian Somers 1379a0b991fSBrian Somers static void 138b6e82f33SBrian Somers throughput_sampler(void *v) 1399a0b991fSBrian Somers { 140b6e82f33SBrian Somers struct pppThroughput *t = (struct pppThroughput *)v; 1415d9e6103SBrian Somers unsigned long long old; 142ab2de065SBrian Somers int uptime, divisor; 1439a0b991fSBrian Somers 144dd7e2610SBrian Somers timer_Stop(&t->Timer); 1459a0b991fSBrian Somers 146ab2de065SBrian Somers uptime = throughput_uptime(t); 147ab2de065SBrian Somers divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 1489a0b991fSBrian Somers old = t->SampleOctets[t->nSample]; 1499a0b991fSBrian Somers t->SampleOctets[t->nSample] = t->OctetsIn + t->OctetsOut; 150ab2de065SBrian Somers t->OctetsPerSecond = (t->SampleOctets[t->nSample] - old) / divisor; 151255aa9e3SBrian Somers if (t->BestOctetsPerSecond < t->OctetsPerSecond) { 1529a0b991fSBrian Somers t->BestOctetsPerSecond = t->OctetsPerSecond; 153ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 154255aa9e3SBrian Somers } 155ab2de065SBrian Somers if (++t->nSample == t->SamplePeriod) 1569a0b991fSBrian Somers t->nSample = 0; 1579a0b991fSBrian Somers 158ab2de065SBrian Somers if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 159ab2de065SBrian Somers (*t->callback.fn)(t->callback.data); 160ab2de065SBrian Somers 161dd7e2610SBrian Somers timer_Start(&t->Timer); 1629a0b991fSBrian Somers } 1639a0b991fSBrian Somers 1649a0b991fSBrian Somers void 1651342caedSBrian Somers throughput_start(struct pppThroughput *t, const char *name, int rolling) 1669a0b991fSBrian Somers { 167ab2de065SBrian Somers int i; 168dd7e2610SBrian Somers timer_Stop(&t->Timer); 169ab2de065SBrian Somers 170ab2de065SBrian Somers for (i = 0; i < t->SamplePeriod; i++) 171ab2de065SBrian Somers t->SampleOctets[i] = 0; 172ab2de065SBrian Somers t->nSample = 0; 173ab2de065SBrian Somers t->OctetsIn = t->OctetsOut = 0; 174ab2de065SBrian Somers t->OctetsPerSecond = t->BestOctetsPerSecond = 0; 175ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 176ab2de065SBrian Somers t->downtime = 0; 1779a0b991fSBrian Somers time(&t->uptime); 178ab2de065SBrian Somers throughput_restart(t, name, rolling); 179ab2de065SBrian Somers } 180ab2de065SBrian Somers 181ab2de065SBrian Somers void 182ab2de065SBrian Somers throughput_restart(struct pppThroughput *t, const char *name, int rolling) 183ab2de065SBrian Somers { 184ab2de065SBrian Somers timer_Stop(&t->Timer); 185ab2de065SBrian Somers t->rolling = rolling ? 1 : 0; 1861342caedSBrian Somers if (t->rolling) { 1879a0b991fSBrian Somers t->Timer.load = SECTICKS; 1889a0b991fSBrian Somers t->Timer.func = throughput_sampler; 1893b0f8d2eSBrian Somers t->Timer.name = name; 1909a0b991fSBrian Somers t->Timer.arg = t; 191dd7e2610SBrian Somers timer_Start(&t->Timer); 192ab2de065SBrian Somers } else { 193ab2de065SBrian Somers t->Timer.load = 0; 194ab2de065SBrian Somers t->Timer.func = NULL; 195ab2de065SBrian Somers t->Timer.name = NULL; 196ab2de065SBrian Somers t->Timer.arg = NULL; 1979a0b991fSBrian Somers } 1989a0b991fSBrian Somers } 1999a0b991fSBrian Somers 2009a0b991fSBrian Somers void 2019a0b991fSBrian Somers throughput_stop(struct pppThroughput *t) 2029a0b991fSBrian Somers { 203ab2de065SBrian Somers if (t->Timer.state != TIMER_STOPPED) 204ab2de065SBrian Somers time(&t->downtime); 205dd7e2610SBrian Somers timer_Stop(&t->Timer); 2069a0b991fSBrian Somers } 2079a0b991fSBrian Somers 2089a0b991fSBrian Somers void 2095d9e6103SBrian Somers throughput_addin(struct pppThroughput *t, long long n) 2109a0b991fSBrian Somers { 2119a0b991fSBrian Somers t->OctetsIn += n; 2129a0b991fSBrian Somers } 2139a0b991fSBrian Somers 2149a0b991fSBrian Somers void 2155d9e6103SBrian Somers throughput_addout(struct pppThroughput *t, long long n) 2169a0b991fSBrian Somers { 2179a0b991fSBrian Somers t->OctetsOut += n; 2189a0b991fSBrian Somers } 21941dbe0c7SBrian Somers 22041dbe0c7SBrian Somers void 22141dbe0c7SBrian Somers throughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 22241dbe0c7SBrian Somers { 22341dbe0c7SBrian Somers if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 22441dbe0c7SBrian Somers int i; 22541dbe0c7SBrian Somers 226ab2de065SBrian Somers for (i = 0; i < t->SamplePeriod; i++) 22741dbe0c7SBrian Somers t->SampleOctets[i] = 0; 22841dbe0c7SBrian Somers t->nSample = 0; 22941dbe0c7SBrian Somers } 23041dbe0c7SBrian Somers 23141dbe0c7SBrian Somers if (clear_type & THROUGHPUT_OVERALL) { 232ab2de065SBrian Somers int divisor; 23341dbe0c7SBrian Somers 234ab2de065SBrian Somers if ((divisor = throughput_uptime(t)) == 0) 235ab2de065SBrian Somers divisor = 1; 2365d9e6103SBrian Somers prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 237ab2de065SBrian Somers (t->OctetsIn + t->OctetsOut) / divisor); 23841dbe0c7SBrian Somers t->OctetsIn = t->OctetsOut = 0; 239ab2de065SBrian Somers t->downtime = 0; 240ab2de065SBrian Somers time(&t->uptime); 24141dbe0c7SBrian Somers } 24241dbe0c7SBrian Somers 24341dbe0c7SBrian Somers if (clear_type & THROUGHPUT_CURRENT) { 2445d9e6103SBrian Somers prompt_Printf(prompt, "current cleared (was %6qu bytes/sec)\n", 24541dbe0c7SBrian Somers t->OctetsPerSecond); 24641dbe0c7SBrian Somers t->OctetsPerSecond = 0; 24741dbe0c7SBrian Somers } 24841dbe0c7SBrian Somers 24941dbe0c7SBrian Somers if (clear_type & THROUGHPUT_PEAK) { 25041dbe0c7SBrian Somers char *time_buf, *last; 25141dbe0c7SBrian Somers 25241dbe0c7SBrian Somers time_buf = ctime(&t->BestOctetsPerSecondTime); 25341dbe0c7SBrian Somers last = time_buf + strlen(time_buf); 25441dbe0c7SBrian Somers if (last > time_buf && *--last == '\n') 25541dbe0c7SBrian Somers *last = '\0'; 2565d9e6103SBrian Somers prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 25741dbe0c7SBrian Somers t->BestOctetsPerSecond, time_buf); 25841dbe0c7SBrian Somers t->BestOctetsPerSecond = 0; 259ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 26041dbe0c7SBrian Somers } 26141dbe0c7SBrian Somers } 262ab2de065SBrian Somers 263ab2de065SBrian Somers void 264ab2de065SBrian Somers throughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 265ab2de065SBrian Somers { 266ab2de065SBrian Somers t->callback.fn = fn; 267ab2de065SBrian Somers t->callback.data = data; 268ab2de065SBrian Somers } 269