Doxyfy userload.h and userload.c.
[ircu2.10.12-pk.git] / ircd / userload.c
1 /*
2  * Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
3  * Written 2/93.  Originally grafted into irc2.7.2g 4/93.
4  * 
5  * Rewritten 9/97 by Carlo Wood (Run) <carlo@runaway.xs4all.nl>
6  * because previous version used ridiculous amounts of memory
7  * (stored all loads of the passed three days ~ 8 megs).
8  *
9  * IRC - Internet Relay Chat, ircd/userload.c
10  * Copyright (C) 1990 University of Oulu, Computing Center
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 1, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * $Id$
27  */
28 #include "config.h"
29
30 #include "userload.h"
31 #include "client.h"
32 #include "ircd.h"
33 #include "msg.h"
34 #include "numnicks.h"
35 #include "querycmds.h"
36 #include "s_misc.h"
37 #include "s_stats.h"
38 #include "send.h"
39 #include "struct.h"
40 #include "sys.h"
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <time.h>
45
46 struct current_load_st current_load;    /**< The current load */
47
48 static struct current_load_st cspm_sum; /**< Number of connections times number
49                                            of seconds per minute. */
50 static struct current_load_st csph_sum; /**< Number of connections times number
51                                            of seconds per hour. */
52 static struct current_load_st cspm[60]; /**< Last 60 minutes */
53 static struct current_load_st csph[72]; /**< Last 72 hours */
54
55 static int m_index; /**< Next entry to use in #cspm. */
56 static int h_index; /**< Next entry to use in #csph. */
57
58 /** Update load average to reflect a change in the local client count.
59  */
60 void update_load(void)
61 {
62   static struct tm tm_now;      /* Current time. */
63   static time_t last_sec;       /* Seconds of last time that
64                                    update_load() called. */
65   static time_t last_min;
66   static time_t last;           /* Last time that update_load() was called. */
67   static struct current_load_st last_load;      /* The load last time that
68                                                    update_load() was called. */
69   static int initialized;       /* Boolean, set when initialized. */
70   int diff_time;        /* Temp. variable used to hold time intervals
71                                    in seconds, minutes or hours. */
72
73   /* Update `current_load' */
74   current_load.client_count = UserStats.local_clients;
75   current_load.conn_count = UserStats.local_clients + UserStats.local_servers;
76
77   /* Nothing needed when still in the same second */
78   if (!(diff_time = CurrentTime - last))
79   {
80     last_load = current_load;   /* Update last_load to be the load last
81                                    time that update_load() was called. */
82     return;
83   }
84
85   /* If we get here we entered a new second */
86
87   /*
88    * Make sure we keep the accurate time in 'tm_now'
89    */
90   if ((tm_now.tm_sec += diff_time) > 59)
91   {
92     /* This is done once every minute */
93     diff_time = tm_now.tm_sec / 60;
94     tm_now.tm_sec -= 60 * diff_time;
95     if ((tm_now.tm_min += diff_time) > 59)
96     {
97       /* This is done once every hour */
98       diff_time = tm_now.tm_min / 60;
99       tm_now.tm_min -= 60 * diff_time;
100       if ((tm_now.tm_hour += diff_time) > 23)
101       {
102         tm_now = *localtime(&CurrentTime);      /* Only called once a day */
103         if (!initialized)
104         {
105           initialized = 1;
106           last_sec = 60;
107           last_min = tm_now.tm_min;
108         }
109       }
110     }
111
112     /* If we get here we entered a new minute */
113
114     /* Finish the calculation of cspm of the last minute first: */
115     diff_time = 60 - last_sec;
116     cspm_sum.conn_count += last_load.conn_count * diff_time;
117     cspm_sum.client_count += last_load.client_count * diff_time;
118     cspm_sum.local_count += last_load.local_count * diff_time;
119
120     /* Add the completed minute to the Connections*Seconds/Hour sum */
121     csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
122     csph_sum.client_count += cspm_sum.client_count - cspm[m_index].client_count;
123     csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
124
125     /* Store the completed minute in an array */
126     cspm[m_index] = cspm_sum;
127
128     /* How long did last_cspm last ? */
129     diff_time = tm_now.tm_min - last_min;
130     last_min = tm_now.tm_min;
131
132     if (diff_time < 0)
133       diff_time += 60;          /* update_load() must be called at
134                                    _least_ once an hour */
135
136     if (diff_time > 1)          /* Did more then one minute pass ? */
137     {
138       /* Calculate the constant load during those extra minutes */
139       cspm_sum.conn_count = last_load.conn_count * 60;
140       cspm_sum.client_count = last_load.client_count * 60;
141       cspm_sum.local_count = last_load.local_count * 60;
142     }
143
144     for (;;)
145     {
146       /* Increase minute index */
147       if (++m_index == 60)
148       {
149         m_index = 0;
150         /* Keep a list of the last 72 hours */
151         csph[h_index] = csph_sum;
152         if (++h_index == 72)
153           h_index = 0;
154       }
155
156       if (--diff_time <= 0)     /* '<' to prevent endless loop if update_load()
157                                    was not called once an hour :/ */
158         break;
159
160       /* Add extra minutes to the Connections*Seconds/Hour sum */
161       csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
162       csph_sum.client_count +=
163           cspm_sum.client_count - cspm[m_index].client_count;
164       csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
165
166       /* Store extra minutes in the array */
167       cspm[m_index] = cspm_sum;
168     }
169
170     /* Now start the calculation of the new minute: */
171     last_sec = tm_now.tm_sec;
172     cspm_sum.conn_count = last_load.conn_count * last_sec;
173     cspm_sum.client_count = last_load.client_count * last_sec;
174     cspm_sum.local_count = last_load.local_count * last_sec;
175   }
176   else
177   {
178     /* A new second, but the same minute as last time */
179     /* How long did last_load last ? */
180     diff_time = tm_now.tm_sec - last_sec;
181     last_sec = tm_now.tm_sec;
182     if (diff_time == 1)         /* Just one second ? */
183     {
184       cspm_sum.conn_count += last_load.conn_count;
185       cspm_sum.client_count += last_load.client_count;
186       cspm_sum.local_count += last_load.local_count;
187     }
188     else
189     {
190       /* More then one second */
191       /* At most 3 integer multiplication per second */
192       cspm_sum.conn_count += last_load.conn_count * diff_time;
193       cspm_sum.client_count += last_load.client_count * diff_time;
194       cspm_sum.local_count += last_load.local_count * diff_time;
195     }
196   }
197   last_load = current_load;     /* Update last_load to be the load last
198                                    time that update_load() was called. */
199   last = CurrentTime;
200 }
201
202 /** Statistics callback to display userload.
203  * @param[in] sptr Client requesting statistics.
204  * @param[in] sd Stats descriptor for request (ignored).
205  * @param[in] param Extra parameter from user (ignored).
206  */
207 void
208 calc_load(struct Client *sptr, const struct StatDesc *sd, char *param)
209 {
210   /* *INDENT-OFF* */
211   static const char *header =
212   /*   ----.-  ----.-  ----  ----  ----   ------------ */
213       "Minute  Hour    Day   Yest. YYest. Userload for:";
214   /* *INDENT-ON* */
215   static const char *what[3] = {
216     "local clients",
217     "total clients",
218     "total connections"
219   };
220   int i, j, times[5][3];        /* [min,hour,day,Yest,YYest]
221                                    [local,client,conn] */
222   int last_m_index = m_index, last_h_index = h_index;
223
224   update_load();                /* We want stats accurate as of *now* */
225
226   if (--last_m_index < 0)
227     last_m_index = 59;
228   times[0][0] = (cspm[last_m_index].local_count + 3) / 6;
229   times[0][1] = (cspm[last_m_index].client_count + 3) / 6;
230   times[0][2] = (cspm[last_m_index].conn_count + 3) / 6;
231
232   times[1][0] = (csph_sum.local_count + 180) / 360;
233   times[1][1] = (csph_sum.client_count + 180) / 360;
234   times[1][2] = (csph_sum.conn_count + 180) / 360;
235
236   for (i = 2; i < 5; ++i)
237   {
238     times[i][0] = 43200;
239     times[i][1] = 43200;
240     times[i][2] = 43200;
241     for (j = 0; j < 24; ++j)
242     {
243       if (--last_h_index < 0)
244         last_h_index = 71;
245       times[i][0] += csph[last_h_index].local_count;
246       times[i][1] += csph[last_h_index].client_count;
247       times[i][2] += csph[last_h_index].conn_count;
248     }
249     times[i][0] /= 86400;
250     times[i][1] /= 86400;
251     times[i][2] /= 86400;
252   }
253
254   sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, header);
255   for (i = 0; i < 3; ++i)
256     sendcmdto_one(&me, CMD_NOTICE, sptr,
257                   "%C :%4d.%1d  %4d.%1d  %4d  %4d  %4d   %s", sptr,
258                   times[0][i] / 10, times[0][i] % 10,
259                   times[1][i] / 10, times[1][i] % 10,
260                   times[2][i], times[3][i], times[4][i], what[i]);
261 }
262
263 /** Initialize the userload statistics. */
264 void initload(void)
265 {
266   memset(&current_load, 0, sizeof(current_load));
267   update_load();                /* Initialize the load list */
268 }