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