throughput.c revision 65178
161374Sdcs/*- 261374Sdcs * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org> 361374Sdcs * All rights reserved. 461374Sdcs * 561374Sdcs * Redistribution and use in source and binary forms, with or without 661374Sdcs * modification, are permitted provided that the following conditions 761374Sdcs * are met: 861374Sdcs * 1. Redistributions of source code must retain the above copyright 961374Sdcs * notice, this list of conditions and the following disclaimer. 1061374Sdcs * 2. Redistributions in binary form must reproduce the above copyright 1161374Sdcs * notice, this list of conditions and the following disclaimer in the 1261374Sdcs * documentation and/or other materials provided with the distribution. 1361374Sdcs * 1461374Sdcs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1561374Sdcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1661374Sdcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1761374Sdcs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1861374Sdcs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1961374Sdcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2061374Sdcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2161374Sdcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2261374Sdcs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2361374Sdcs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2461374Sdcs * SUCH DAMAGE. 2561374Sdcs * 2661374Sdcs * $FreeBSD: head/usr.sbin/ppp/throughput.c 65178 2000-08-28 22:44:54Z brian $ 2761374Sdcs */ 2861374Sdcs 2961374Sdcs#include <sys/types.h> 3061374Sdcs 3161374Sdcs#include <stdio.h> 3261374Sdcs#include <stdlib.h> 3361374Sdcs#include <string.h> 3461374Sdcs#include <termios.h> 3561374Sdcs#include <time.h> 3661374Sdcs 3761374Sdcs#include "log.h" 3861374Sdcs#include "timer.h" 3961374Sdcs#include "throughput.h" 4076116Sdcs#include "descriptor.h" 4161374Sdcs#include "prompt.h" 4261374Sdcs 4361374Sdcs 4461374Sdcsvoid 4561374Sdcsthroughput_init(struct pppThroughput *t, int period) 4661374Sdcs{ 4761374Sdcs t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0; 4865617Sdcs t->SamplePeriod = period; 4965617Sdcs t->in.SampleOctets = (long long *) 5065617Sdcs calloc(period, sizeof *t->in.SampleOctets); 5165617Sdcs t->in.OctetsPerSecond = 0; 5276116Sdcs t->out.SampleOctets = (long long *) 5361374Sdcs calloc(period, sizeof *t->out.SampleOctets); 5461374Sdcs t->out.OctetsPerSecond = 0; 5576116Sdcs t->BestOctetsPerSecond = 0; 5661374Sdcs t->nSample = 0; 5761374Sdcs time(&t->BestOctetsPerSecondTime); 5861374Sdcs memset(&t->Timer, '\0', sizeof t->Timer); 5961374Sdcs t->Timer.name = "throughput"; 6061374Sdcs t->uptime = 0; 6161374Sdcs t->downtime = 0; 6261374Sdcs t->rolling = 0; 6361374Sdcs t->callback.data = NULL; 6461374Sdcs t->callback.fn = NULL; 6561374Sdcs throughput_stop(t); 6661374Sdcs} 6761374Sdcs 6861374Sdcsvoid 6961374Sdcsthroughput_destroy(struct pppThroughput *t) 7061374Sdcs{ 7161374Sdcs if (t && t->in.SampleOctets) { 7261374Sdcs throughput_stop(t); 7361374Sdcs free(t->in.SampleOctets); 7461374Sdcs free(t->out.SampleOctets); 7561374Sdcs t->in.SampleOctets = NULL; 7661374Sdcs t->out.SampleOctets = NULL; 7761374Sdcs } 7861374Sdcs} 7961374Sdcs 8061374Sdcsint 8161374Sdcsthroughput_uptime(struct pppThroughput *t) 8261374Sdcs{ 8361374Sdcs time_t downat; 8461374Sdcs 8561374Sdcs downat = t->downtime ? t->downtime : time(NULL); 8661374Sdcs if (t->uptime && downat < t->uptime) { 8761374Sdcs /* Euch ! The clock's gone back ! */ 8861374Sdcs int i; 8961374Sdcs 9061374Sdcs for (i = 0; i < t->SamplePeriod; i++) 9161374Sdcs t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 9261374Sdcs t->nSample = 0; 9361374Sdcs t->uptime = downat; 9461374Sdcs } 9561374Sdcs return t->uptime ? downat - t->uptime : 0; 9661374Sdcs} 9761374Sdcs 9861374Sdcsvoid 9961374Sdcsthroughput_disp(struct pppThroughput *t, struct prompt *prompt) 10061374Sdcs{ 10161374Sdcs int secs_up, divisor; 10261374Sdcs 10361374Sdcs secs_up = throughput_uptime(t); 10461374Sdcs prompt_Printf(prompt, "Connect time: %d:%02d:%02d", secs_up / 3600, 10561374Sdcs (secs_up / 60) % 60, secs_up % 60); 10661374Sdcs if (t->downtime) 10761374Sdcs prompt_Printf(prompt, " - down at %s", ctime(&t->downtime)); 10861374Sdcs else 10961374Sdcs prompt_Printf(prompt, "\n"); 11061374Sdcs 11161374Sdcs divisor = secs_up ? secs_up : 1; 11261374Sdcs prompt_Printf(prompt, "%llu octets in, %llu octets out\n", 11361374Sdcs t->OctetsIn, t->OctetsOut); 11461374Sdcs prompt_Printf(prompt, "%llu packets in, %llu packets out\n", 11561374Sdcs t->PacketsIn, t->PacketsOut); 11661374Sdcs if (t->rolling) { 11761374Sdcs prompt_Printf(prompt, " overall %6qu bytes/sec\n", 11861374Sdcs (t->OctetsIn + t->OctetsOut) / divisor); 11961374Sdcs prompt_Printf(prompt, " %s %6qu bytes/sec in, %6qu bytes/sec out " 12061374Sdcs "(over the last %d secs)\n", 12161374Sdcs t->downtime ? "average " : "currently", 12261374Sdcs t->in.OctetsPerSecond, t->out.OctetsPerSecond, 12361374Sdcs secs_up > t->SamplePeriod ? t->SamplePeriod : secs_up); 12461374Sdcs prompt_Printf(prompt, " peak %6qu bytes/sec on %s", 12561374Sdcs t->BestOctetsPerSecond, ctime(&t->BestOctetsPerSecondTime)); 12661374Sdcs } else 12761374Sdcs prompt_Printf(prompt, "Overall %llu bytes/sec\n", 12861374Sdcs (t->OctetsIn + t->OctetsOut) / divisor); 12961374Sdcs} 13061374Sdcs 13161374Sdcs 13261374Sdcsvoid 13361374Sdcsthroughput_log(struct pppThroughput *t, int level, const char *title) 13461374Sdcs{ 13561374Sdcs if (t->uptime) { 13661374Sdcs int secs_up; 13761374Sdcs 13861374Sdcs secs_up = throughput_uptime(t); 13961374Sdcs if (title == NULL) 14061374Sdcs title = ""; 14161374Sdcs log_Printf(level, "%s%sConnect time: %d secs: %llu octets in, %llu octets" 14261374Sdcs " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn, 14361374Sdcs t->OctetsOut); 14461374Sdcs log_Printf(level, "%s%s: %llu packets in, %llu packets out\n", 14561374Sdcs title, *title ? ": " : "", t->PacketsIn, t->PacketsOut); 14661374Sdcs if (secs_up == 0) 14761374Sdcs secs_up = 1; 14861374Sdcs if (t->rolling) 14961374Sdcs log_Printf(level, " total %llu bytes/sec, peak %llu bytes/sec on %s", 15061374Sdcs (t->OctetsIn + t->OctetsOut) / secs_up, t->BestOctetsPerSecond, 15161374Sdcs ctime(&t->BestOctetsPerSecondTime)); 15261374Sdcs else 15361374Sdcs log_Printf(level, " total %llu bytes/sec\n", 15461374Sdcs (t->OctetsIn + t->OctetsOut) / secs_up); 15561374Sdcs } 15661374Sdcs} 15761374Sdcs 15861374Sdcsstatic void 15961374Sdcsthroughput_sampler(void *v) 16061374Sdcs{ 16161374Sdcs struct pppThroughput *t = (struct pppThroughput *)v; 16261374Sdcs unsigned long long old; 16361374Sdcs int uptime, divisor; 16461374Sdcs unsigned long long octets; 16561374Sdcs 16661374Sdcs timer_Stop(&t->Timer); 16761374Sdcs 16861374Sdcs uptime = throughput_uptime(t); 16961374Sdcs divisor = uptime < t->SamplePeriod ? uptime + 1 : t->SamplePeriod; 17061374Sdcs 17161374Sdcs old = t->in.SampleOctets[t->nSample]; 17261374Sdcs t->in.SampleOctets[t->nSample] = t->OctetsIn; 17361374Sdcs t->in.OctetsPerSecond = (t->in.SampleOctets[t->nSample] - old) / divisor; 17461374Sdcs 17561374Sdcs old = t->out.SampleOctets[t->nSample]; 17661374Sdcs t->out.SampleOctets[t->nSample] = t->OctetsOut; 17761374Sdcs t->out.OctetsPerSecond = (t->out.SampleOctets[t->nSample] - old) / divisor; 17861374Sdcs 17961374Sdcs octets = t->in.OctetsPerSecond + t->out.OctetsPerSecond; 18061374Sdcs if (t->BestOctetsPerSecond < octets) { 18161374Sdcs t->BestOctetsPerSecond = octets; 18261374Sdcs time(&t->BestOctetsPerSecondTime); 18361374Sdcs } 18461374Sdcs 18561374Sdcs if (++t->nSample == t->SamplePeriod) 18661374Sdcs t->nSample = 0; 18761374Sdcs 18861374Sdcs if (t->callback.fn != NULL && uptime >= t->SamplePeriod) 18961374Sdcs (*t->callback.fn)(t->callback.data); 19061374Sdcs 19161374Sdcs timer_Start(&t->Timer); 19261374Sdcs} 19361374Sdcs 19461374Sdcsvoid 19561374Sdcsthroughput_start(struct pppThroughput *t, const char *name, int rolling) 19661374Sdcs{ 19761374Sdcs int i; 19861374Sdcs timer_Stop(&t->Timer); 19961374Sdcs 20061374Sdcs for (i = 0; i < t->SamplePeriod; i++) 20161374Sdcs t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 20261374Sdcs t->nSample = 0; 20361374Sdcs t->OctetsIn = t->OctetsOut = 0; 20461374Sdcs t->in.OctetsPerSecond = t->out.OctetsPerSecond = t->BestOctetsPerSecond = 0; 20561374Sdcs time(&t->BestOctetsPerSecondTime); 20661374Sdcs t->downtime = 0; 20761374Sdcs time(&t->uptime); 20861374Sdcs throughput_restart(t, name, rolling); 20961374Sdcs} 21061374Sdcs 21161374Sdcsvoid 21261374Sdcsthroughput_restart(struct pppThroughput *t, const char *name, int rolling) 21361374Sdcs{ 21461374Sdcs timer_Stop(&t->Timer); 21565617Sdcs t->rolling = rolling ? 1 : 0; 21665617Sdcs if (t->rolling) { 21765617Sdcs t->Timer.load = SECTICKS; 21865617Sdcs t->Timer.func = throughput_sampler; 21965617Sdcs t->Timer.name = name; 22065617Sdcs t->Timer.arg = t; 22165617Sdcs timer_Start(&t->Timer); 22265617Sdcs } else { 22365617Sdcs t->Timer.load = 0; 22465617Sdcs t->Timer.func = NULL; 22565617Sdcs t->Timer.name = NULL; 22665617Sdcs t->Timer.arg = NULL; 22765617Sdcs } 22865617Sdcs} 22965617Sdcs 23065617Sdcsvoid 23165617Sdcsthroughput_stop(struct pppThroughput *t) 23265617Sdcs{ 23365617Sdcs if (t->Timer.state != TIMER_STOPPED) 23465617Sdcs time(&t->downtime); 23565617Sdcs timer_Stop(&t->Timer); 23665617Sdcs} 23765617Sdcs 23865617Sdcsvoid 23965617Sdcsthroughput_addin(struct pppThroughput *t, long long n) 24065617Sdcs{ 24165617Sdcs t->OctetsIn += n; 24265617Sdcs t->PacketsIn++; 24365617Sdcs} 24465617Sdcs 24565617Sdcsvoid 24665617Sdcsthroughput_addout(struct pppThroughput *t, long long n) 24765677Sdfr{ 24865677Sdfr t->OctetsOut += n; 24965617Sdcs t->PacketsOut++; 25065617Sdcs} 25165617Sdcs 25265617Sdcsvoid 25365617Sdcsthroughput_clear(struct pppThroughput *t, int clear_type, struct prompt *prompt) 25465617Sdcs{ 25565617Sdcs if (clear_type & (THROUGHPUT_OVERALL|THROUGHPUT_CURRENT)) { 25665617Sdcs int i; 25765617Sdcs 25865617Sdcs for (i = 0; i < t->SamplePeriod; i++) 25965617Sdcs t->in.SampleOctets[i] = t->out.SampleOctets[i] = 0; 26065617Sdcs t->nSample = 0; 26165617Sdcs } 26265617Sdcs 26365617Sdcs if (clear_type & THROUGHPUT_OVERALL) { 26465617Sdcs int divisor; 26565617Sdcs 26665617Sdcs if ((divisor = throughput_uptime(t)) == 0) 26765617Sdcs divisor = 1; 26865617Sdcs prompt_Printf(prompt, "overall cleared (was %6qu bytes/sec)\n", 26965617Sdcs (t->OctetsIn + t->OctetsOut) / divisor); 27065617Sdcs t->OctetsIn = t->OctetsOut = 0; 27165617Sdcs t->downtime = 0; 27265617Sdcs time(&t->uptime); 27365617Sdcs } 27465617Sdcs 27565617Sdcs if (clear_type & THROUGHPUT_CURRENT) { 27665617Sdcs prompt_Printf(prompt, "current cleared (was %6qu bytes/sec in," 27765617Sdcs " %6qu bytes/sec out)\n", 27865617Sdcs t->in.OctetsPerSecond, t->out.OctetsPerSecond); 27965677Sdfr t->in.OctetsPerSecond = t->out.OctetsPerSecond = 0; 28065677Sdfr } 28176116Sdcs 28276116Sdcs if (clear_type & THROUGHPUT_PEAK) { 28365617Sdcs char *time_buf, *last; 28465617Sdcs 28565617Sdcs time_buf = ctime(&t->BestOctetsPerSecondTime); 28665617Sdcs last = time_buf + strlen(time_buf); 28765617Sdcs if (last > time_buf && *--last == '\n') 28865617Sdcs *last = '\0'; 28965617Sdcs prompt_Printf(prompt, "peak cleared (was %6qu bytes/sec on %s)\n", 29065617Sdcs t->BestOctetsPerSecond, time_buf); 29165617Sdcs t->BestOctetsPerSecond = 0; 29265617Sdcs time(&t->BestOctetsPerSecondTime); 29365617Sdcs } 29465617Sdcs} 29565617Sdcs 29665617Sdcsvoid 29765617Sdcsthroughput_callback(struct pppThroughput *t, void (*fn)(void *), void *data) 29865617Sdcs{ 29965617Sdcs t->callback.fn = fn; 30065617Sdcs t->callback.data = data; 30165617Sdcs} 30265617Sdcs