X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=blobdiff_plain;f=ircd%2Fuserload.c;fp=ircd%2Fuserload.c;h=6bc641b788cf69a7b7eb035d538435fa4ff41f63;hp=0000000000000000000000000000000000000000;hb=0400a5a6479398d82526785c18c0df8bc8b92dce;hpb=d17e10da972ce5776c60b4c317267c6abe0e1ead diff --git a/ircd/userload.c b/ircd/userload.c new file mode 100644 index 0000000..6bc641b --- /dev/null +++ b/ircd/userload.c @@ -0,0 +1,270 @@ +/* + * Userload module by Michael L. VanLoon (mlv) + * Written 2/93. Originally grafted into irc2.7.2g 4/93. + * + * Rewritten 9/97 by Carlo Wood (Run) + * because previous version used ridiculous amounts of memory + * (stored all loads of the passed three days ~ 8 megs). + * + * IRC - Internet Relay Chat, ircd/userload.c + * Copyright (C) 1990 University of Oulu, Computing Center + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/** @file + * @brief Userload tracking and statistics. + * @version $Id$ + */ +#include "config.h" + +#include "userload.h" +#include "client.h" +#include "ircd.h" +#include "msg.h" +#include "numnicks.h" +#include "querycmds.h" +#include "s_misc.h" +#include "s_stats.h" +#include "send.h" +#include "struct.h" +#include "sys.h" + +#include +#include +#include + +struct current_load_st current_load; /**< The current load */ + +static struct current_load_st cspm_sum; /**< Number of connections times number + of seconds per minute. */ +static struct current_load_st csph_sum; /**< Number of connections times number + of seconds per hour. */ +static struct current_load_st cspm[60]; /**< Last 60 minutes */ +static struct current_load_st csph[72]; /**< Last 72 hours */ + +static int m_index; /**< Next entry to use in #cspm. */ +static int h_index; /**< Next entry to use in #csph. */ + +/** Update load average to reflect a change in the local client count. + */ +void update_load(void) +{ + static struct tm tm_now; /* Current time. */ + static time_t last_sec; /* Seconds of last time that + update_load() called. */ + static time_t last_min; + static time_t last; /* Last time that update_load() was called. */ + static struct current_load_st last_load; /* The load last time that + update_load() was called. */ + static int initialized; /* Boolean, set when initialized. */ + int diff_time; /* Temp. variable used to hold time intervals + in seconds, minutes or hours. */ + + /* Update `current_load' */ + current_load.client_count = UserStats.local_clients; + current_load.conn_count = UserStats.local_clients + UserStats.local_servers; + + /* Nothing needed when still in the same second */ + if (!(diff_time = CurrentTime - last)) + { + last_load = current_load; /* Update last_load to be the load last + time that update_load() was called. */ + return; + } + + /* If we get here we entered a new second */ + + /* + * Make sure we keep the accurate time in 'tm_now' + */ + if ((tm_now.tm_sec += diff_time) > 59) + { + /* This is done once every minute */ + diff_time = tm_now.tm_sec / 60; + tm_now.tm_sec -= 60 * diff_time; + if ((tm_now.tm_min += diff_time) > 59) + { + /* This is done once every hour */ + diff_time = tm_now.tm_min / 60; + tm_now.tm_min -= 60 * diff_time; + if ((tm_now.tm_hour += diff_time) > 23) + { + tm_now = *localtime(&CurrentTime); /* Only called once a day */ + if (!initialized) + { + initialized = 1; + last_sec = 60; + last_min = tm_now.tm_min; + } + } + } + + /* If we get here we entered a new minute */ + + /* Finish the calculation of cspm of the last minute first: */ + diff_time = 60 - last_sec; + cspm_sum.conn_count += last_load.conn_count * diff_time; + cspm_sum.client_count += last_load.client_count * diff_time; + cspm_sum.local_count += last_load.local_count * diff_time; + + /* Add the completed minute to the Connections*Seconds/Hour sum */ + csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count; + csph_sum.client_count += cspm_sum.client_count - cspm[m_index].client_count; + csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count; + + /* Store the completed minute in an array */ + cspm[m_index] = cspm_sum; + + /* How long did last_cspm last ? */ + diff_time = tm_now.tm_min - last_min; + last_min = tm_now.tm_min; + + if (diff_time < 0) + diff_time += 60; /* update_load() must be called at + _least_ once an hour */ + + if (diff_time > 1) /* Did more then one minute pass ? */ + { + /* Calculate the constant load during those extra minutes */ + cspm_sum.conn_count = last_load.conn_count * 60; + cspm_sum.client_count = last_load.client_count * 60; + cspm_sum.local_count = last_load.local_count * 60; + } + + for (;;) + { + /* Increase minute index */ + if (++m_index == 60) + { + m_index = 0; + /* Keep a list of the last 72 hours */ + csph[h_index] = csph_sum; + if (++h_index == 72) + h_index = 0; + } + + if (--diff_time <= 0) /* '<' to prevent endless loop if update_load() + was not called once an hour :/ */ + break; + + /* Add extra minutes to the Connections*Seconds/Hour sum */ + csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count; + csph_sum.client_count += + cspm_sum.client_count - cspm[m_index].client_count; + csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count; + + /* Store extra minutes in the array */ + cspm[m_index] = cspm_sum; + } + + /* Now start the calculation of the new minute: */ + last_sec = tm_now.tm_sec; + cspm_sum.conn_count = last_load.conn_count * last_sec; + cspm_sum.client_count = last_load.client_count * last_sec; + cspm_sum.local_count = last_load.local_count * last_sec; + } + else + { + /* A new second, but the same minute as last time */ + /* How long did last_load last ? */ + diff_time = tm_now.tm_sec - last_sec; + last_sec = tm_now.tm_sec; + if (diff_time == 1) /* Just one second ? */ + { + cspm_sum.conn_count += last_load.conn_count; + cspm_sum.client_count += last_load.client_count; + cspm_sum.local_count += last_load.local_count; + } + else + { + /* More then one second */ + /* At most 3 integer multiplication per second */ + cspm_sum.conn_count += last_load.conn_count * diff_time; + cspm_sum.client_count += last_load.client_count * diff_time; + cspm_sum.local_count += last_load.local_count * diff_time; + } + } + last_load = current_load; /* Update last_load to be the load last + time that update_load() was called. */ + last = CurrentTime; +} + +/** Statistics callback to display userload. + * @param[in] sptr Client requesting statistics. + * @param[in] sd Stats descriptor for request (ignored). + * @param[in] param Extra parameter from user (ignored). + */ +void +calc_load(struct Client *sptr, const struct StatDesc *sd, char *param) +{ + /* *INDENT-OFF* */ + static const char *header = + /* ----.- ----.- ---- ---- ---- ------------ */ + "Minute Hour Day Yest. YYest. Userload for:"; + /* *INDENT-ON* */ + static const char *what[3] = { + "local clients", + "total clients", + "total connections" + }; + int i, j, times[5][3]; /* [min,hour,day,Yest,YYest] + [local,client,conn] */ + int last_m_index = m_index, last_h_index = h_index; + + update_load(); /* We want stats accurate as of *now* */ + + if (--last_m_index < 0) + last_m_index = 59; + times[0][0] = (cspm[last_m_index].local_count + 3) / 6; + times[0][1] = (cspm[last_m_index].client_count + 3) / 6; + times[0][2] = (cspm[last_m_index].conn_count + 3) / 6; + + times[1][0] = (csph_sum.local_count + 180) / 360; + times[1][1] = (csph_sum.client_count + 180) / 360; + times[1][2] = (csph_sum.conn_count + 180) / 360; + + for (i = 2; i < 5; ++i) + { + times[i][0] = 43200; + times[i][1] = 43200; + times[i][2] = 43200; + for (j = 0; j < 24; ++j) + { + if (--last_h_index < 0) + last_h_index = 71; + times[i][0] += csph[last_h_index].local_count; + times[i][1] += csph[last_h_index].client_count; + times[i][2] += csph[last_h_index].conn_count; + } + times[i][0] /= 86400; + times[i][1] /= 86400; + times[i][2] /= 86400; + } + + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, header); + for (i = 0; i < 3; ++i) + sendcmdto_one(&me, CMD_NOTICE, sptr, + "%C :%4d.%1d %4d.%1d %4d %4d %4d %s", sptr, + times[0][i] / 10, times[0][i] % 10, + times[1][i] / 10, times[1][i] % 10, + times[2][i], times[3][i], times[4][i], what[i]); +} + +/** Initialize the userload statistics. */ +void initload(void) +{ + memset(¤t_load, 0, sizeof(current_load)); + update_load(); /* Initialize the load list */ +}