Commit 1e0b323a authored by Per Cederqvist's avatar Per Cederqvist
Browse files

New file, that collects some statistical information about the

operation of the server.
parent 395d370f
/*
* Copyright (C) 2003 Lysator Academic Computer Association.
*
* This file is part of the LysKOM server.
*
* LysKOM is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* LysKOM is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with LysKOM; see the file COPYING. If not, write to
* Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
* or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
* Please mail bug reports to bug-lyskom@lysator.liu.se.
*/
/*
* stats.c -- Handle statistical information, such as load averages.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include "timewrap.h"
#include <string.h>
#include <stdio.h>
#include "stats.h"
#include "log.h"
#include "lyskomd.h"
#define FACT_00 (1) /* 1 second */
#define FACT_0 (15) /* 15 seconds */
#define FACT_1 ( 4 * FACT_0) /* 1 minute */
#define FACT_2 ( 5 * FACT_1) /* 5 minutes */
#define FACT_3 ( 3 * FACT_2) /* 15 minutes */
#define N_FACTS 5
#define HISTORY_LENGTH (FACT_3)
/* Define this to debug the average counting code. This will slow
down the code a lot, so it is not recommended for production use. */
#undef DEBUG_STATS
struct avg_status {
struct timeval when;
long value;
float acc;
float avg_history[HISTORY_LENGTH];
double avenrun[N_FACTS];
long updates[N_FACTS];
};
static struct avg_status status[NUM_STAT];
static struct avg_status copy[NUM_STAT];
static const int factors[] = {
FACT_00,
FACT_0,
FACT_1,
FACT_2,
FACT_3,
};
static int
ind(unsigned long sec,
unsigned int offset)
{
int ret = (sec + offset) % HISTORY_LENGTH;
assert(ret >= 0);
assert(ret < HISTORY_LENGTH);
return ret;
}
#ifdef DEBUG_STATS
static void
dump_stats(struct avg_status *s)
{
int st;
int i;
fprintf(stderr, "START DUMP\n");
for (st = 0; st < NUM_STAT; st++)
{
fprintf(stderr, "stats for type %d: when=%ld:%ld value=%ld acc=%f\n",
st, (long)s[st].when.tv_sec, (long)s[st].when.tv_usec,
s[st].value, s[st].acc);
fprintf(stderr, " indices:");
fprintf(stderr, " ():0:%d", ind(s[st].when.tv_sec, 0));
for (i = 0; i < N_FACTS; i++)
fprintf(stderr, " %d:%d:%d", i, factors[i], ind(s[st].when.tv_sec,
-factors[i]));
fprintf(stderr, "\n avenrun:");
for (i = 0; i < N_FACTS; i++)
fprintf(stderr, " %f", s[st].avenrun[i]);
fprintf(stderr, "\n updates:");
for (i = 0; i < N_FACTS; i++)
fprintf(stderr, " %ld", s[st].updates[i]);
fprintf(stderr, "\n history:");
for (i = 0; i < HISTORY_LENGTH; i++)
fprintf(stderr, " %f", s[st].avg_history[i]);
fprintf(stderr, "\n");
}
}
#endif
void
init_stats(void)
{
int t;
int i;
struct timeval now;
assert(sizeof(factors)/sizeof(factors[0]) == N_FACTS);
assert(factors[N_FACTS-1] == HISTORY_LENGTH);
gettimeofday(&now, NULL);
for (t = 0; t < NUM_STAT; t++)
{
status[t].when = now;
status[t].value = 0;
status[t].acc = 0.0;
for (i = 0; i < HISTORY_LENGTH; i++)
status[t].avg_history[i] = 0.0;
for (i = 0; i < N_FACTS; i++)
{
status[t].avenrun[i] = 0.0;
status[t].updates[i] = 0;
}
}
}
static void
update_history(struct avg_status *s,
time_t end,
float value)
{
int i;
for (; s->when.tv_sec < end; s->when.tv_sec++)
{
for (i = 0; i < N_FACTS; i++)
s->avenrun[i] += (value - s->avg_history[ind(s->when.tv_sec,
-factors[i])])
/ (double)factors[i];
s->avg_history[ind(s->when.tv_sec, 0)] = value;
}
}
void
update_stat(enum stat_type st,
long delta)
{
struct timeval now;
long time_delta;
int i;
struct avg_status *s = &status[st];
assert(st < STAT_FIRST_EVENT || delta >= 0);
memcpy(copy, status, sizeof(status));
gettimeofday(&now, NULL);
if (now.tv_sec == s->when.tv_sec)
{
if (st < STAT_FIRST_EVENT)
{
time_delta = now.tv_usec - s->when.tv_usec;
if (time_delta != 0)
s->acc += (float)s->value / time_delta;
s->when.tv_usec = now.tv_usec;
}
}
else if (now.tv_sec - s->when.tv_sec <= HISTORY_LENGTH)
{
if (st < STAT_FIRST_EVENT)
{
time_delta = 1000000 - s->when.tv_usec;
if (time_delta != 0)
s->acc += (float)s->value / time_delta;
}
else
s->acc = s->value;
update_history(s, s->when.tv_sec+1, s->acc);
if (st >= STAT_FIRST_EVENT)
{
s->acc = 0;
s->value = 0;
}
update_history(s, now.tv_sec, s->value);
assert(s->when.tv_sec == now.tv_sec);
if (st < STAT_FIRST_EVENT)
{
if (now.tv_usec == 0)
s->acc = 0;
else
s->acc = (float)s->value / now.tv_usec;
s->when.tv_usec = now.tv_usec;
}
}
else
{
if (st >= STAT_FIRST_EVENT)
{
s->acc = 0;
s->value = 0;
}
for (i = 0; i < N_FACTS; i++)
s->avenrun[i] = s->value;
for (i = 0; i < HISTORY_LENGTH; i++)
s->avg_history[i] = s->value;
if (st < STAT_FIRST_EVENT)
{
if (now.tv_usec == 0)
s->acc = 0;
else
s->acc = (float)s->value / now.tv_usec;
}
s->when = now;
}
s->value += delta;
for (i = 0; i < N_FACTS; i++)
s->updates[i]++;
if (s->value < 0)
{
kom_log("update_stat(%d, %ld): current value became negative: %ld\n",
st, delta, s->value);
s->value = 0;
}
#ifdef DEBUG_STATS
if (check_stat("update_stats") > 0)
{
kom_log("This was caused by an update of delta=%ld for type %d\n",
delta, st);
kom_log("Dump of before:\n");
dump_stats(copy);
kom_log("Dump of after:\n");
dump_stats(status);
}
#endif
}
extern int
check_stat(const char *when)
{
struct avg_status *s;
double acc;
double err;
float val;
int st;
int f;
int i;
int changes = 0;
for (st = 0; st < NUM_STAT; st++)
{
s = &status[st];
for (f = 0; f < N_FACTS; f++)
{
acc = 0;
for (i = 0; i < factors[f]; i++)
{
val = s->avg_history[ind(s->when.tv_sec, -i-1)];
assert(val >= 0);
acc += val;
}
acc /= factors[f];
err = acc - s->avenrun[f];
if (err < 0)
err = -err;
if ((acc < 1e-6 && err > 1e-5)
|| (acc >= 1e-6 && err / acc > 0.01))
{
kom_log("Accumulated rounding errors fixed (%s) after"
" %ld updates (type=%d, f=%d, factor=%d): %f => %f\n",
when,
s->updates[f], st, f, factors[f], s->avenrun[f], acc);
s->avenrun[f] = acc;
s->updates[f] = 0;
changes++;
}
}
}
return changes;
}
/*
* Copyright (C) 2003 Lysator Academic Computer Association.
*
* This file is part of the LysKOM server.
*
* LysKOM is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* LysKOM is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with LysKOM; see the file COPYING. If not, write to
* Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
* or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
* Please mail bug reports to bug-lyskom@lysator.liu.se.
*/
/*
* stats.h -- Handle statistical information, such as load averages.
*/
enum stat_type {
/* Average values. */
STAT_RUN_QUEUE,
#if 0
STAT_DNS_QUEUE,
STAT_IDENT_QUEUE,
#endif
/* Events. */
STAT_FIRST_EVENT,
STAT_PROCESSED_CALLS = STAT_FIRST_EVENT,
STAT_RUN_QUEUE_ENTER,
STAT_RUN_QUEUE_LEAVE,
NUM_STAT
};
extern void init_stats(void);
extern void update_stat(enum stat_type st, long delta);
extern int check_stat(const char *when);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment