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.
27 * @brief Userload tracking and statistics.
28 * @version $Id: userload.c,v 1.11 2004/10/05 04:21:36 entrope Exp $
37 #include "querycmds.h"
48 struct current_load_st current_load
; /**< The current load */
50 static struct current_load_st cspm_sum
; /**< Number of connections times number
51 of seconds per minute. */
52 static struct current_load_st csph_sum
; /**< Number of connections times number
53 of seconds per hour. */
54 static struct current_load_st cspm
[60]; /**< Last 60 minutes */
55 static struct current_load_st csph
[72]; /**< Last 72 hours */
57 static int m_index
; /**< Next entry to use in #cspm. */
58 static int h_index
; /**< Next entry to use in #csph. */
60 /** Update load average to reflect a change in the local client count.
62 void update_load(void)
64 static struct tm tm_now
; /* Current time. */
65 static time_t last_sec
; /* Seconds of last time that
66 update_load() called. */
67 static time_t last_min
;
68 static time_t last
; /* Last time that update_load() was called. */
69 static struct current_load_st last_load
; /* The load last time that
70 update_load() was called. */
71 static int initialized
; /* Boolean, set when initialized. */
72 int diff_time
; /* Temp. variable used to hold time intervals
73 in seconds, minutes or hours. */
75 /* Update `current_load' */
76 current_load
.client_count
= UserStats
.local_clients
;
77 current_load
.conn_count
= UserStats
.local_clients
+ UserStats
.local_servers
;
79 /* Nothing needed when still in the same second */
80 if (!(diff_time
= CurrentTime
- last
))
82 last_load
= current_load
; /* Update last_load to be the load last
83 time that update_load() was called. */
87 /* If we get here we entered a new second */
90 * Make sure we keep the accurate time in 'tm_now'
92 if ((tm_now
.tm_sec
+= diff_time
) > 59)
94 /* This is done once every minute */
95 diff_time
= tm_now
.tm_sec
/ 60;
96 tm_now
.tm_sec
-= 60 * diff_time
;
97 if ((tm_now
.tm_min
+= diff_time
) > 59)
99 /* This is done once every hour */
100 diff_time
= tm_now
.tm_min
/ 60;
101 tm_now
.tm_min
-= 60 * diff_time
;
102 if ((tm_now
.tm_hour
+= diff_time
) > 23)
104 tm_now
= *localtime(&CurrentTime
); /* Only called once a day */
109 last_min
= tm_now
.tm_min
;
114 /* If we get here we entered a new minute */
116 /* Finish the calculation of cspm of the last minute first: */
117 diff_time
= 60 - last_sec
;
118 cspm_sum
.conn_count
+= last_load
.conn_count
* diff_time
;
119 cspm_sum
.client_count
+= last_load
.client_count
* diff_time
;
120 cspm_sum
.local_count
+= last_load
.local_count
* diff_time
;
122 /* Add the completed minute to the Connections*Seconds/Hour sum */
123 csph_sum
.conn_count
+= cspm_sum
.conn_count
- cspm
[m_index
].conn_count
;
124 csph_sum
.client_count
+= cspm_sum
.client_count
- cspm
[m_index
].client_count
;
125 csph_sum
.local_count
+= cspm_sum
.local_count
- cspm
[m_index
].local_count
;
127 /* Store the completed minute in an array */
128 cspm
[m_index
] = cspm_sum
;
130 /* How long did last_cspm last ? */
131 diff_time
= tm_now
.tm_min
- last_min
;
132 last_min
= tm_now
.tm_min
;
135 diff_time
+= 60; /* update_load() must be called at
136 _least_ once an hour */
138 if (diff_time
> 1) /* Did more then one minute pass ? */
140 /* Calculate the constant load during those extra minutes */
141 cspm_sum
.conn_count
= last_load
.conn_count
* 60;
142 cspm_sum
.client_count
= last_load
.client_count
* 60;
143 cspm_sum
.local_count
= last_load
.local_count
* 60;
148 /* Increase minute index */
152 /* Keep a list of the last 72 hours */
153 csph
[h_index
] = csph_sum
;
158 if (--diff_time
<= 0) /* '<' to prevent endless loop if update_load()
159 was not called once an hour :/ */
162 /* Add extra minutes to the Connections*Seconds/Hour sum */
163 csph_sum
.conn_count
+= cspm_sum
.conn_count
- cspm
[m_index
].conn_count
;
164 csph_sum
.client_count
+=
165 cspm_sum
.client_count
- cspm
[m_index
].client_count
;
166 csph_sum
.local_count
+= cspm_sum
.local_count
- cspm
[m_index
].local_count
;
168 /* Store extra minutes in the array */
169 cspm
[m_index
] = cspm_sum
;
172 /* Now start the calculation of the new minute: */
173 last_sec
= tm_now
.tm_sec
;
174 cspm_sum
.conn_count
= last_load
.conn_count
* last_sec
;
175 cspm_sum
.client_count
= last_load
.client_count
* last_sec
;
176 cspm_sum
.local_count
= last_load
.local_count
* last_sec
;
180 /* A new second, but the same minute as last time */
181 /* How long did last_load last ? */
182 diff_time
= tm_now
.tm_sec
- last_sec
;
183 last_sec
= tm_now
.tm_sec
;
184 if (diff_time
== 1) /* Just one second ? */
186 cspm_sum
.conn_count
+= last_load
.conn_count
;
187 cspm_sum
.client_count
+= last_load
.client_count
;
188 cspm_sum
.local_count
+= last_load
.local_count
;
192 /* More then one second */
193 /* At most 3 integer multiplication per second */
194 cspm_sum
.conn_count
+= last_load
.conn_count
* diff_time
;
195 cspm_sum
.client_count
+= last_load
.client_count
* diff_time
;
196 cspm_sum
.local_count
+= last_load
.local_count
* diff_time
;
199 last_load
= current_load
; /* Update last_load to be the load last
200 time that update_load() was called. */
204 /** Statistics callback to display userload.
205 * @param[in] sptr Client requesting statistics.
206 * @param[in] sd Stats descriptor for request (ignored).
207 * @param[in] param Extra parameter from user (ignored).
210 calc_load(struct Client
*sptr
, const struct StatDesc
*sd
, char *param
)
213 static const char *header
=
214 /* ----.- ----.- ---- ---- ---- ------------ */
215 "Minute Hour Day Yest. YYest. Userload for:";
217 static const char *what
[3] = {
222 int i
, j
, times
[5][3]; /* [min,hour,day,Yest,YYest]
223 [local,client,conn] */
224 int last_m_index
= m_index
, last_h_index
= h_index
;
226 update_load(); /* We want stats accurate as of *now* */
228 if (--last_m_index
< 0)
230 times
[0][0] = (cspm
[last_m_index
].local_count
+ 3) / 6;
231 times
[0][1] = (cspm
[last_m_index
].client_count
+ 3) / 6;
232 times
[0][2] = (cspm
[last_m_index
].conn_count
+ 3) / 6;
234 times
[1][0] = (csph_sum
.local_count
+ 180) / 360;
235 times
[1][1] = (csph_sum
.client_count
+ 180) / 360;
236 times
[1][2] = (csph_sum
.conn_count
+ 180) / 360;
238 for (i
= 2; i
< 5; ++i
)
243 for (j
= 0; j
< 24; ++j
)
245 if (--last_h_index
< 0)
247 times
[i
][0] += csph
[last_h_index
].local_count
;
248 times
[i
][1] += csph
[last_h_index
].client_count
;
249 times
[i
][2] += csph
[last_h_index
].conn_count
;
251 times
[i
][0] /= 86400;
252 times
[i
][1] /= 86400;
253 times
[i
][2] /= 86400;
256 sendcmdto_one(&me
, CMD_NOTICE
, sptr
, "%C :%s", sptr
, header
);
257 for (i
= 0; i
< 3; ++i
)
258 sendcmdto_one(&me
, CMD_NOTICE
, sptr
,
259 "%C :%4d.%1d %4d.%1d %4d %4d %4d %s", sptr
,
260 times
[0][i
] / 10, times
[0][i
] % 10,
261 times
[1][i
] / 10, times
[1][i
] % 10,
262 times
[2][i
], times
[3][i
], times
[4][i
], what
[i
]);
265 /** Initialize the userload statistics. */
268 memset(¤t_load
, 0, sizeof(current_load
));
269 update_load(); /* Initialize the load list */