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