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 * 2697d92980SPeter Wemm * $FreeBSD$ 279a0b991fSBrian Somers */ 289a0b991fSBrian Somers 292764b86aSBrian Somers #include <sys/types.h> 309a0b991fSBrian Somers 316eafd353SBrian Somers #include <stdarg.h> 329a0b991fSBrian Somers #include <stdio.h> 33ab2de065SBrian Somers #include <stdlib.h> 34e3c70ce9SBrian Somers #include <string.h> 3585b542cfSBrian Somers #include <termios.h> 369a0b991fSBrian Somers #include <time.h> 379a0b991fSBrian Somers 38b6e82f33SBrian Somers #include "log.h" 399a0b991fSBrian Somers #include "timer.h" 409a0b991fSBrian Somers #include "throughput.h" 4185b542cfSBrian Somers #include "descriptor.h" 4285b542cfSBrian Somers #include "prompt.h" 439a0b991fSBrian Somers 4491cbd2eeSBrian Somers 459a0b991fSBrian Somers void 46ab2de065SBrian Somers throughput_init(struct pppThroughput *t, int period) 479a0b991fSBrian Somers { 48794c9bbcSBrian Somers t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 49ab2de065SBrian Somers t->SamplePeriod = period; 5091cbd2eeSBrian Somers t->in.SampleOctets = (long long *) 5191cbd2eeSBrian Somers calloc(period, sizeof *t->in.SampleOctets); 5291cbd2eeSBrian Somers t->in.OctetsPerSecond = 0; 5391cbd2eeSBrian Somers t->out.SampleOctets = (long long *) 5491cbd2eeSBrian Somers calloc(period, sizeof *t->out.SampleOctets); 5591cbd2eeSBrian Somers t->out.OctetsPerSecond = 0; 5691cbd2eeSBrian Somers t->BestOctetsPerSecond = 0; 57ab2de065SBrian Somers t->nSample = 0; 58ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 59e3c70ce9SBrian Somers memset(&t->Timer, '\0', sizeof t->Timer); 603b0f8d2eSBrian Somers t->Timer.name = "throughput"; 61565e35e5SBrian Somers t->uptime = 0; 62ab2de065SBrian Somers t->downtime = 0; 631342caedSBrian Somers t->rolling = 0; 64ab2de065SBrian Somers t->callback.data = NULL; 65ab2de065SBrian Somers t->callback.fn = NULL; 669a0b991fSBrian Somers throughput_stop(t); 679a0b991fSBrian Somers } 689a0b991fSBrian Somers 699a0b991fSBrian Somers void 70ab2de065SBrian Somers throughput_destroy(struct pppThroughput *t) 71ab2de065SBrian Somers { 7291cbd2eeSBrian Somers if (t && t->in.SampleOctets) { 73ab2de065SBrian Somers throughput_stop(t); 7491cbd2eeSBrian Somers free(t->in.SampleOctets); 7591cbd2eeSBrian Somers free(t->out.SampleOctets); 7691cbd2eeSBrian Somers t->in.SampleOctets = NULL; 7791cbd2eeSBrian Somers t->out.SampleOctets = NULL; 78ab2de065SBrian Somers } 79ab2de065SBrian Somers } 80ab2de065SBrian Somers 81ab2de065SBrian Somers int 82ab2de065SBrian Somers throughput_uptime(struct pppThroughput *t) 83ab2de065SBrian Somers { 84ab2de065SBrian Somers time_t downat; 85ab2de065SBrian Somers 86ab2de065SBrian Somers downat = t->downtime ? t->downtime : time(NULL); 87dbb69e52SBrian Somers if (t->uptime && downat < t->uptime) { 88dbb69e52SBrian Somers /* Euch ! The clock's gone back ! */ 89dbb69e52SBrian Somers int i; 90dbb69e52SBrian Somers 91dbb69e52SBrian Somers for (i = 0; i < t->SamplePeriod; i++) 9291cbd2eeSBrian Somers t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 93dbb69e52SBrian Somers t->nSample = 0; 94dbb69e52SBrian Somers t->uptime = downat; 95dbb69e52SBrian Somers } 96ab2de065SBrian Somers return t->uptime ? downat - t->uptime : 0; 97ab2de065SBrian Somers } 98ab2de065SBrian Somers 99ab2de065SBrian Somers void 100b6217683SBrian Somers throughput_disp(struct pppThroughput *t, struct prompt *prompt) 1019a0b991fSBrian Somers { 102ab2de065SBrian Somers int secs_up, divisor; 1039a0b991fSBrian Somers 104ab2de065SBrian Somers secs_up = throughput_uptime(t); 105ab2de065SBrian Somers prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 106ab2de065SBrian Somers (secs_up / 60) % 60, secs_up % 60); 107ab2de065SBrian Somers if (t->downtime) 108ab2de065SBrian Somers prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 109ab2de065SBrian Somers else 110ab2de065SBrian Somers prompt_Printf(prompt, "\n"); 111ab2de065SBrian Somers 112ab2de065SBrian Somers divisor = secs_up ? secs_up : 1; 113e531f89aSBrian Somers prompt_Printf(prompt, "%llu octets in, %llu octets out\n", 11485b542cfSBrian Somers t->OctetsIn, t->OctetsOut); 115794c9bbcSBrian Somers prompt_Printf(prompt, "%llu packets in, %llu packets out\n", 116794c9bbcSBrian Somers t->PacketsIn, t->PacketsOut); 1171342caedSBrian Somers if (t->rolling) { 1185d9e6103SBrian Somers prompt_Printf(prompt, " overall %6qu bytes/sec\n", 119ab2de065SBrian Somers (t->OctetsIn + t->OctetsOut) / divisor); 12091cbd2eeSBrian Somers prompt_Printf(prompt, " %s %6qu bytes/sec in, %6qu bytes/sec out " 12191cbd2eeSBrian Somers "(over the last %d secs)\n", 12291cbd2eeSBrian Somers t->downtime ? "average " : "currently", 12391cbd2eeSBrian Somers t->in.OctetsPerSecond, t->out.OctetsPerSecond, 124ab2de065SBrian Somers secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 1255d9e6103SBrian Somers prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 126255aa9e3SBrian Somers t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 1279a0b991fSBrian Somers } else 128e531f89aSBrian Somers prompt_Printf(prompt, "Overall %llu bytes/sec\n", 129ab2de065SBrian Somers (t->OctetsIn + t->OctetsOut) / divisor); 1309a0b991fSBrian Somers } 1319a0b991fSBrian Somers 1329a0b991fSBrian Somers 1339a0b991fSBrian Somers void 1349a0b991fSBrian Somers throughput_log(struct pppThroughput *t, int level, const char *title) 1359a0b991fSBrian Somers { 1369a0b991fSBrian Somers if (t->uptime) { 1379a0b991fSBrian Somers int secs_up; 1389a0b991fSBrian Somers 139ab2de065SBrian Somers secs_up = throughput_uptime(t); 14091cbd2eeSBrian Somers if (title == NULL) 14191cbd2eeSBrian Somers title = ""; 14291cbd2eeSBrian Somers log_Printf(level, "%s%sConnect time: %d secs: %llu octets in, %llu octets" 14391cbd2eeSBrian Somers " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn, 14491cbd2eeSBrian Somers t->OctetsOut); 1457e1c2e33SBrian Somers log_Printf(level, "%s%s%llu packets in, %llu packets out\n", 146794c9bbcSBrian Somers title, *title ? ": " : "", t->PacketsIn, t->PacketsOut); 1479a0b991fSBrian Somers if (secs_up == 0) 1489a0b991fSBrian Somers secs_up = 1; 1491342caedSBrian Somers if (t->rolling) 150e531f89aSBrian Somers log_Printf(level, " total %llu bytes/sec, peak %llu bytes/sec on %s", 151255aa9e3SBrian Somers (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 152255aa9e3SBrian Somers ctime(&t->BestOctetsPerSecondTime)); 1539a0b991fSBrian Somers else 154e531f89aSBrian Somers log_Printf(level, " total %llu bytes/sec\n", 1559a0b991fSBrian Somers (t->OctetsIn + t->OctetsOut) / secs_up); 1569a0b991fSBrian Somers } 1579a0b991fSBrian Somers } 1589a0b991fSBrian Somers 1599a0b991fSBrian Somers static void 160b6e82f33SBrian Somers throughput_sampler(void *v) 1619a0b991fSBrian Somers { 162b6e82f33SBrian Somers struct pppThroughput *t = (struct pppThroughput *)v; 1635d9e6103SBrian Somers unsigned long long old; 164ab2de065SBrian Somers int uptime, divisor; 16591cbd2eeSBrian Somers unsigned long long octets; 1669a0b991fSBrian Somers 167dd7e2610SBrian Somers timer_Stop(&t->Timer); 1689a0b991fSBrian Somers 169ab2de065SBrian Somers uptime = throughput_uptime(t); 170ab2de065SBrian Somers divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 17191cbd2eeSBrian Somers 17291cbd2eeSBrian Somers old = t->in.SampleOctets[t->nSample]; 17391cbd2eeSBrian Somers t->in.SampleOctets[t->nSample] = t->OctetsIn; 17491cbd2eeSBrian Somers t->in.OctetsPerSecond = (t->in.SampleOctets[t->nSample] - old) / divisor; 17591cbd2eeSBrian Somers 17691cbd2eeSBrian Somers old = t->out.SampleOctets[t->nSample]; 17791cbd2eeSBrian Somers t->out.SampleOctets[t->nSample] = t->OctetsOut; 17891cbd2eeSBrian Somers t->out.OctetsPerSecond = (t->out.SampleOctets[t->nSample] - old) / divisor; 17991cbd2eeSBrian Somers 18091cbd2eeSBrian Somers octets = t->in.OctetsPerSecond + t->out.OctetsPerSecond; 18191cbd2eeSBrian Somers if (t->BestOctetsPerSecond < octets) { 18291cbd2eeSBrian Somers t->BestOctetsPerSecond = octets; 183ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 184255aa9e3SBrian Somers } 18591cbd2eeSBrian Somers 186ab2de065SBrian Somers if (++t->nSample == t->SamplePeriod) 1879a0b991fSBrian Somers t->nSample = 0; 1889a0b991fSBrian Somers 189ab2de065SBrian Somers if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 190ab2de065SBrian Somers (*t->callback.fn)(t->callback.data); 191ab2de065SBrian Somers 192dd7e2610SBrian Somers timer_Start(&t->Timer); 1939a0b991fSBrian Somers } 1949a0b991fSBrian Somers 1959a0b991fSBrian Somers void 1961342caedSBrian Somers throughput_start(struct pppThroughput *t, const char *name, int rolling) 1979a0b991fSBrian Somers { 198ab2de065SBrian Somers int i; 199dd7e2610SBrian Somers timer_Stop(&t->Timer); 200ab2de065SBrian Somers 201ab2de065SBrian Somers for (i = 0; i < t->SamplePeriod; i++) 20291cbd2eeSBrian Somers t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 203ab2de065SBrian Somers t->nSample = 0; 204*3532ad3eSNick Hibma t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 20591cbd2eeSBrian Somers t->in.OctetsPerSecond = t->out.OctetsPerSecond = t->BestOctetsPerSecond = 0; 206ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 207ab2de065SBrian Somers t->downtime = 0; 2089a0b991fSBrian Somers time(&t->uptime); 209ab2de065SBrian Somers throughput_restart(t, name, rolling); 210ab2de065SBrian Somers } 211ab2de065SBrian Somers 212ab2de065SBrian Somers void 213ab2de065SBrian Somers throughput_restart(struct pppThroughput *t, const char *name, int rolling) 214ab2de065SBrian Somers { 215ab2de065SBrian Somers timer_Stop(&t->Timer); 216ab2de065SBrian Somers t->rolling = rolling ? 1 : 0; 2171342caedSBrian Somers if (t->rolling) { 2189a0b991fSBrian Somers t->Timer.load = SECTICKS; 2199a0b991fSBrian Somers t->Timer.func = throughput_sampler; 2203b0f8d2eSBrian Somers t->Timer.name = name; 2219a0b991fSBrian Somers t->Timer.arg = t; 222dd7e2610SBrian Somers timer_Start(&t->Timer); 223ab2de065SBrian Somers } else { 224ab2de065SBrian Somers t->Timer.load = 0; 225ab2de065SBrian Somers t->Timer.func = NULL; 226ab2de065SBrian Somers t->Timer.name = NULL; 227ab2de065SBrian Somers t->Timer.arg = NULL; 2289a0b991fSBrian Somers } 2299a0b991fSBrian Somers } 2309a0b991fSBrian Somers 2319a0b991fSBrian Somers void 2329a0b991fSBrian Somers throughput_stop(struct pppThroughput *t) 2339a0b991fSBrian Somers { 234ab2de065SBrian Somers if (t->Timer.state != TIMER_STOPPED) 235ab2de065SBrian Somers time(&t->downtime); 236dd7e2610SBrian Somers timer_Stop(&t->Timer); 2379a0b991fSBrian Somers } 2389a0b991fSBrian Somers 2399a0b991fSBrian Somers void 2405d9e6103SBrian Somers throughput_addin(struct pppThroughput *t, long long n) 2419a0b991fSBrian Somers { 2429a0b991fSBrian Somers t->OctetsIn += n; 243794c9bbcSBrian Somers t->PacketsIn++; 2449a0b991fSBrian Somers } 2459a0b991fSBrian Somers 2469a0b991fSBrian Somers void 2475d9e6103SBrian Somers throughput_addout(struct pppThroughput *t, long long n) 2489a0b991fSBrian Somers { 2499a0b991fSBrian Somers t->OctetsOut += n; 250794c9bbcSBrian Somers t->PacketsOut++; 2519a0b991fSBrian Somers } 25241dbe0c7SBrian Somers 25341dbe0c7SBrian Somers void 25441dbe0c7SBrian Somers throughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 25541dbe0c7SBrian Somers { 25641dbe0c7SBrian Somers if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 25741dbe0c7SBrian Somers int i; 25841dbe0c7SBrian Somers 259ab2de065SBrian Somers for (i = 0; i < t->SamplePeriod; i++) 26091cbd2eeSBrian Somers t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 26141dbe0c7SBrian Somers t->nSample = 0; 26241dbe0c7SBrian Somers } 26341dbe0c7SBrian Somers 26441dbe0c7SBrian Somers if (clear_type & THROUGHPUT_OVERALL) { 265ab2de065SBrian Somers int divisor; 26641dbe0c7SBrian Somers 267ab2de065SBrian Somers if ((divisor = throughput_uptime(t)) == 0) 268ab2de065SBrian Somers divisor = 1; 2695d9e6103SBrian Somers prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 270ab2de065SBrian Somers (t->OctetsIn + t->OctetsOut) / divisor); 271*3532ad3eSNick Hibma t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 272ab2de065SBrian Somers t->downtime = 0; 273ab2de065SBrian Somers time(&t->uptime); 27441dbe0c7SBrian Somers } 27541dbe0c7SBrian Somers 27641dbe0c7SBrian Somers if (clear_type & THROUGHPUT_CURRENT) { 27791cbd2eeSBrian Somers prompt_Printf(prompt, "current cleared (was %6qu bytes/sec in," 27891cbd2eeSBrian Somers " %6qu bytes/sec out)\n", 27991cbd2eeSBrian Somers t->in.OctetsPerSecond, t->out.OctetsPerSecond); 28091cbd2eeSBrian Somers t->in.OctetsPerSecond = t->out.OctetsPerSecond = 0; 28141dbe0c7SBrian Somers } 28241dbe0c7SBrian Somers 28341dbe0c7SBrian Somers if (clear_type & THROUGHPUT_PEAK) { 28441dbe0c7SBrian Somers char *time_buf, *last; 28541dbe0c7SBrian Somers 28641dbe0c7SBrian Somers time_buf = ctime(&t->BestOctetsPerSecondTime); 28741dbe0c7SBrian Somers last = time_buf + strlen(time_buf); 28841dbe0c7SBrian Somers if (last > time_buf && *--last == '\n') 28941dbe0c7SBrian Somers *last = '\0'; 2905d9e6103SBrian Somers prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 29141dbe0c7SBrian Somers t->BestOctetsPerSecond, time_buf); 29241dbe0c7SBrian Somers t->BestOctetsPerSecond = 0; 293ab2de065SBrian Somers time(&t->BestOctetsPerSecondTime); 29441dbe0c7SBrian Somers } 29541dbe0c7SBrian Somers } 296ab2de065SBrian Somers 297ab2de065SBrian Somers void 298ab2de065SBrian Somers throughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 299ab2de065SBrian Somers { 300ab2de065SBrian Somers t->callback.fn = fn; 301ab2de065SBrian Somers t->callback.data = data; 302ab2de065SBrian Somers } 303