2 * Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
3 * Written 2/93. Originally grafted into irc2.7.2g 4/93.
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).
9 * IRC - Internet Relay Chat, ircd/userload.c
10 * Copyright (C) 1990 University of Oulu, Computing Center
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)
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.
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.
32 #include "querycmds.h"
42 struct current_load_st current_load; /* The current load */
44 static struct current_load_st cspm_sum; /* Number of connections times number
45 of seconds per minute. */
46 static struct current_load_st csph_sum; /* Number of connections times number
47 of seconds per hour. */
48 static struct current_load_st cspm[60]; /* Last 60 minutes */
49 static struct current_load_st csph[72]; /* Last 72 hours */
51 static int m_index, h_index; /* Array indexes */
56 * A new connection was added or removed.
58 void update_load(void)
60 static struct tm tm_now; /* Current time. */
61 static time_t last_sec; /* Seconds of last time that
62 update_load() called. */
63 static time_t last_min;
64 static time_t last; /* Last time that update_load() was called. */
65 static struct current_load_st last_load; /* The load last time that
66 update_load() was called. */
67 static int initialized; /* Boolean, set when initialized. */
68 int diff_time; /* Temp. variable used to hold time intervals
69 in seconds, minutes or hours. */
71 /* Update `current_load' */
72 current_load.client_count = UserStats.local_clients;
73 current_load.conn_count = UserStats.local_clients + UserStats.local_servers;
75 /* Nothing needed when still in the same second */
76 if (!(diff_time = CurrentTime - last))
78 last_load = current_load; /* Update last_load to be the load last
79 time that update_load() was called. */
83 /* If we get here we entered a new second */
86 * Make sure we keep the accurate time in 'tm_now'
88 if ((tm_now.tm_sec += diff_time) > 59)
90 /* This is done once every minute */
91 diff_time = tm_now.tm_sec / 60;
92 tm_now.tm_sec -= 60 * diff_time;
93 if ((tm_now.tm_min += diff_time) > 59)
95 /* This is done once every hour */
96 diff_time = tm_now.tm_min / 60;
97 tm_now.tm_min -= 60 * diff_time;
98 if ((tm_now.tm_hour += diff_time) > 23)
100 tm_now = *localtime(&CurrentTime); /* Only called once a day */
105 last_min = tm_now.tm_min;
110 /* If we get here we entered a new minute */
112 /* Finish the calculation of cspm of the last minute first: */
113 diff_time = 60 - last_sec;
114 cspm_sum.conn_count += last_load.conn_count * diff_time;
115 cspm_sum.client_count += last_load.client_count * diff_time;
116 cspm_sum.local_count += last_load.local_count * diff_time;
118 /* Add the completed minute to the Connections*Seconds/Hour sum */
119 csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
120 csph_sum.client_count += cspm_sum.client_count - cspm[m_index].client_count;
121 csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
123 /* Store the completed minute in an array */
124 cspm[m_index] = cspm_sum;
126 /* How long did last_cspm last ? */
127 diff_time = tm_now.tm_min - last_min;
128 last_min = tm_now.tm_min;
131 diff_time += 60; /* update_load() must be called at
132 _least_ once an hour */
134 if (diff_time > 1) /* Did more then one minute pass ? */
136 /* Calculate the constant load during those extra minutes */
137 cspm_sum.conn_count = last_load.conn_count * 60;
138 cspm_sum.client_count = last_load.client_count * 60;
139 cspm_sum.local_count = last_load.local_count * 60;
144 /* Increase minute index */
148 /* Keep a list of the last 72 hours */
149 csph[h_index] = csph_sum;
154 if (--diff_time <= 0) /* '<' to prevent endless loop if update_load()
155 was not called once an hour :/ */
158 /* Add extra minutes to the Connections*Seconds/Hour sum */
159 csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
160 csph_sum.client_count +=
161 cspm_sum.client_count - cspm[m_index].client_count;
162 csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
164 /* Store extra minutes in the array */
165 cspm[m_index] = cspm_sum;
168 /* Now start the calculation of the new minute: */
169 last_sec = tm_now.tm_sec;
170 cspm_sum.conn_count = last_load.conn_count * last_sec;
171 cspm_sum.client_count = last_load.client_count * last_sec;
172 cspm_sum.local_count = last_load.local_count * last_sec;
176 /* A new second, but the same minute as last time */
177 /* How long did last_load last ? */
178 diff_time = tm_now.tm_sec - last_sec;
179 last_sec = tm_now.tm_sec;
180 if (diff_time == 1) /* Just one second ? */
182 cspm_sum.conn_count += last_load.conn_count;
183 cspm_sum.client_count += last_load.client_count;
184 cspm_sum.local_count += last_load.local_count;
188 /* More then one second */
189 /* At most 3 integer multiplication per second */
190 cspm_sum.conn_count += last_load.conn_count * diff_time;
191 cspm_sum.client_count += last_load.client_count * diff_time;
192 cspm_sum.local_count += last_load.local_count * diff_time;
195 last_load = current_load; /* Update last_load to be the load last
196 time that update_load() was called. */
200 void calc_load(struct Client *sptr)
203 static const char *header =
204 /* ----.- ----.- ---- ---- ---- ------------ */
205 "Minute Hour Day Yest. YYest. Userload for:";
207 static const char *what[3] = {
212 int i, j, times[5][3]; /* [min,hour,day,Yest,YYest]
213 [local,client,conn] */
214 int last_m_index = m_index, last_h_index = h_index;
216 update_load(); /* We want stats accurate as of *now* */
218 if (--last_m_index < 0)
220 times[0][0] = (cspm[last_m_index].local_count + 3) / 6;
221 times[0][1] = (cspm[last_m_index].client_count + 3) / 6;
222 times[0][2] = (cspm[last_m_index].conn_count + 3) / 6;
224 times[1][0] = (csph_sum.local_count + 180) / 360;
225 times[1][1] = (csph_sum.client_count + 180) / 360;
226 times[1][2] = (csph_sum.conn_count + 180) / 360;
228 for (i = 2; i < 5; ++i)
233 for (j = 0; j < 24; ++j)
235 if (--last_h_index < 0)
237 times[i][0] += csph[last_h_index].local_count;
238 times[i][1] += csph[last_h_index].client_count;
239 times[i][2] += csph[last_h_index].conn_count;
241 times[i][0] /= 86400;
242 times[i][1] /= 86400;
243 times[i][2] /= 86400;
246 if (MyUser(sptr) || Protocol(sptr->from) < 10)
248 sendto_one(sptr, ":%s NOTICE %s :%s", me.name, sptr->name, header);
249 for (i = 0; i < 3; ++i)
251 ":%s NOTICE %s :%4d.%1d %4d.%1d %4d %4d %4d %s",
253 times[0][i] / 10, times[0][i] % 10,
254 times[1][i] / 10, times[1][i] % 10,
255 times[2][i], times[3][i], times[4][i], what[i]);
259 sendto_one(sptr, "%s NOTICE %s%s :%s",
260 NumServ(&me), NumNick(sptr), header);
261 for (i = 0; i < 3; ++i)
263 "%s NOTICE %s%s :%4d.%1d %4d.%1d %4d %4d %4d %s",
264 NumServ(&me), NumNick(sptr),
265 times[0][i] / 10, times[0][i] % 10,
266 times[1][i] / 10, times[1][i] % 10,
267 times[2][i], times[3][i], times[4][i], what[i]);
273 memset(¤t_load, 0, sizeof(current_load));
274 update_load(); /* Initialize the load list */