SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2004 David Decotigny
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
017 */
018 
019 #include <hwcore/irq.h>
020 #include <sos/kmalloc.h>
021 #include <sos/assert.h>
022 #include <sos/calcload.h>
023 
024 
025 /**
026  * Multiplicative factor to display digits after the decimal dot. The
027  * higher the value, the higher the precision, but the higher the risk
028  * that the value you get is incorrect (integer overflow).
029  *
030  * The CPU ratios will be correctly displayed as long as:
031  *    2^32 > (900 * HZ * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR)
032  * The "900" above means 900s because the load is computed over 15mn (900s).
033  * HZ is the frequency of the timer tick because the load is updated
034  * at each timer tick.
035  * The "100" above is the multiplication factor to get the ratio value
036  * between 0 and 100 (instead of 0-1).
037  *
038  * The maximum CPU sustainable load that will be correctly displayed
039  * is given by the formula:
040  *    (2^32 - 1) / (900 * HZ * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR)
041  * With HZ=100, these maximum sustainable loads are respectively
042  * 47.721, 477.21 and 4772.1 with
043  * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR being respectively 1000, 100
044  * and 10.
045  *
046  * Hence, among these formulaes, the most limitative one is that
047  * concerning the CPU ratios (because of the "100" factor). Actually,
048  * for HZ=100, the only correct value is 10.
049  */
050 #define SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR 10 /* 1/10 resolution */
051 
052 
053 /**
054  * To compute the load, at each clock tick we store the number of
055  * threads ready in kernel/user mode, and the kind of the thread that
056  * is executing (user or kernel mode): this is stored in
057  * current_load_entry. We then compute the sum of these numbers over 3
058  * periods of time: 1 minute, 5 minutes, 15 minutes. This is the role
059  * of the sliding windows data structures. A "sliding window" is only
060  * the synthetic sum of these figures, not a real sliding window of
061  * load_entries. At each timer tick and everytime the load is updated,
062  * the computations are in O(1).
063  *
064  * All the sliding windows share the main "recorded_load" array of
065  * load_entries for that; its role is to store the last 15mns of load
066  * data, which encompasses the data for the 1mn, 5mn and 15mn sliding
067  * windows.
068  */
069 
070 /* Max number of seconds that we record (ie number of entries in
071    recorded_loads) */
072 #define NB_SECS 900
073 
074 
075 /* An entry in the longest sliding window */
076 struct load_entry
077 {
078   sos_ui32_t nb_ticks;
079 
080   sos_ui32_t nb_user_running;
081   sos_ui32_t nb_kernel_running;
082 
083   sos_ui32_t nb_user_ready;
084   sos_ui32_t nb_kernel_ready;
085 };
086 
087 struct load_entry current_load_entry;
088 
089 
090 /* The longest sliding window */
091 struct recorded_loads
092 {
093   sos_ui32_t most_recent;
094   sos_ui32_t max_entries;
095 
096   struct load_entry *load_entries;
097 };
098 
099 #define LOAD_GET_ENTRY(loads,age) \
100   (&((loads).load_entries[( (loads).max_entries + (loads).most_recent - (age))\
101                           % ((loads).max_entries)]))
102 
103 /* A sliding window, we manage one for each time interval */
104 struct sliding_window
105 {
106   sos_ui32_t max_entries;
107   sos_ui32_t nb_entries;
108 
109   sos_ui32_t sigma_nb_ticks;
110   sos_ui32_t sigma_nb_user_running;
111   sos_ui32_t sigma_nb_kernel_running;
112   sos_ui32_t sigma_nb_user_ready;
113   sos_ui32_t sigma_nb_kernel_ready;
114 };
115 
116 
117 /* The main sliding window */
118 static struct recorded_loads recorded_loads;
119 
120 /* The sliding windows for 3 tims intervals: 1min, 5min, 15min */
121 static struct sliding_window load_1mn, load_5mn, load_15mn;
122 
123 /* Forward declaration */
124 static struct sos_timeout_action calcload_timeout;
125 static void calcload_routine(struct sos_timeout_action *a);
126 
127 
128 static void _reinit_load_subsystem()
129 {
130   memset(& recorded_loads, 0x0, sizeof(recorded_loads));
131   memset(& current_load_entry, 0x0, sizeof(struct load_entry));
132   memset(& load_1mn, 0x0, sizeof(load_1mn));
133   memset(& load_5mn, 0x0, sizeof(load_5mn));
134   memset(& load_15mn, 0x0, sizeof(load_15mn));
135 }
136 
137 
138 sos_ret_t sos_load_subsystem_setup(void)
139 {
140   struct sos_time period;
141   _reinit_load_subsystem();
142 
143   if (recorded_loads.load_entries)
144     sos_kfree((sos_vaddr_t) recorded_loads.load_entries);
145   _reinit_load_subsystem();
146 
147   /* Allocate 900 entries to store 15mn of data (because 15minutes =
148      900s) */
149   recorded_loads.max_entries = NB_SECS;
150   recorded_loads.load_entries
151     = (struct load_entry*) sos_kmalloc(NB_SECS * sizeof(struct load_entry),
152                                        0);
153   if (! recorded_loads.load_entries)
154     {
155       return -SOS_ENOMEM;
156     }
157 
158   /* Compute the number of entries in each sliding window */
159   load_1mn.max_entries  = 60;
160   load_5mn.max_entries  = 300;
161   load_15mn.max_entries = 900;
162 
163   /* Program the load computation action */
164   sos_time_init_action(& calcload_timeout);
165   period.sec = 1; period.nanosec = 0;
166   return sos_time_register_action_relative(& calcload_timeout,
167                                            & period,
168                                            calcload_routine,
169                                            NULL);
170 }
171 
172 
173 /* Shift the given sliding window to record the current_load_entry */
174 static void update_sliding_window(struct sliding_window *w)
175 {
176   /*
177    * Compute the value of the sum over the sliding window
178    */
179 
180   /* Take the new value into account */
181   w->sigma_nb_ticks          += current_load_entry.nb_ticks;
182   w->sigma_nb_user_running   += current_load_entry.nb_user_running;
183   w->sigma_nb_kernel_running += current_load_entry.nb_kernel_running;
184   w->sigma_nb_user_ready     += current_load_entry.nb_user_ready;
185   w->sigma_nb_kernel_ready   += current_load_entry.nb_kernel_ready;
186 
187   /* Remove the oldest entry, if it is going to be popped out of the
188      sliding window */
189   if (w->nb_entries < w->max_entries)
190     {
191       w->nb_entries ++;
192     }
193   else
194     {
195       struct load_entry * oldest_entry;
196       oldest_entry = LOAD_GET_ENTRY(recorded_loads, w->nb_entries - 1);
197       w->sigma_nb_ticks          -= oldest_entry->nb_ticks;
198       w->sigma_nb_user_running   -= oldest_entry->nb_user_running;
199       w->sigma_nb_kernel_running -= oldest_entry->nb_kernel_running;
200       w->sigma_nb_user_ready     -= oldest_entry->nb_user_ready;
201       w->sigma_nb_kernel_ready   -= oldest_entry->nb_kernel_ready;
202     }
203 }
204 
205 
206 /* The timeout action responsible for computing the CPU load */
207 static void calcload_routine(struct sos_timeout_action *a)
208 {
209   struct load_entry * new_head;
210   struct sos_time delay;
211 
212   if (! recorded_loads.load_entries)
213     return;
214 
215   /* Update the sliding windows */
216   update_sliding_window(& load_1mn);
217   update_sliding_window(& load_5mn);
218   update_sliding_window(& load_15mn);
219 
220   /* Move the head of the list forward */
221   recorded_loads.most_recent
222     = (recorded_loads.most_recent + 1) % recorded_loads.max_entries;
223 
224   /* Update the new head */
225   new_head = & recorded_loads.load_entries[recorded_loads.most_recent];
226   memcpy(new_head, & current_load_entry, sizeof(current_load_entry));
227 
228   /* Reset the current load entry */
229   memset(& current_load_entry, 0x0, sizeof(current_load_entry));
230 
231   /* Program next occurence of the action */
232   delay.sec = 1;
233   delay.nanosec = 0;
234   sos_time_register_action_relative(a, & delay, calcload_routine, NULL);
235 }
236 
237 
238 sos_ret_t sos_load_do_timer_tick(sos_bool_t cur_is_user,
239                                  sos_ui32_t nb_user_ready,
240                                  sos_ui32_t nb_kernel_ready)
241 {
242   sos_ui32_t flags;
243 
244   sos_disable_IRQs(flags);
245   current_load_entry.nb_ticks ++;
246   current_load_entry.nb_user_ready += nb_user_ready;
247   current_load_entry.nb_kernel_ready += nb_kernel_ready;
248   if (cur_is_user)
249     current_load_entry.nb_user_running ++;
250   else
251     current_load_entry.nb_kernel_running ++;
252   sos_restore_IRQs(flags);
253 
254   return SOS_OK;
255 }
256 
257 
258 void sos_load_to_string(char dest[11], sos_ui32_t load_value)
259 {
260   sos_bool_t print0 = FALSE;
261   sos_ui32_t d;
262 
263 #define PUTCH(c) ({ *dest = (c); dest ++; })
264 
265   for (d = 1000000000UL ; d > 0 ; d /= 10)
266     {
267       sos_ui32_t digit = (load_value / d) % 10;
268 
269       if (digit > 0)
270         {
271           PUTCH(digit + '0');
272           print0 = TRUE;
273         }
274       else if (print0)
275         PUTCH('0');
276       
277       if (d == SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR)
278         {
279           if (! print0)
280             PUTCH('0');
281 
282           PUTCH('.');
283           print0 = TRUE;
284         }
285     }
286   *dest = '\0';
287 }
288 
289 
290 void sos_load_get_uload(sos_ui32_t * _load_1mn,
291                         sos_ui32_t * _load_5mn,
292                         sos_ui32_t * _load_15mn)
293 {
294   sos_ui32_t flags;
295 
296   if (load_1mn.sigma_nb_ticks < 1)
297     return;
298 
299   sos_disable_IRQs(flags);
300   *_load_1mn  = ( load_1mn.sigma_nb_user_ready
301                   + load_1mn.sigma_nb_user_running)
302                 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
303                 / load_1mn.sigma_nb_ticks;
304   *_load_5mn  = ( load_5mn.sigma_nb_user_ready
305                   + load_5mn.sigma_nb_user_running)
306                 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
307                 / load_5mn.sigma_nb_ticks;
308   *_load_15mn  = ( load_15mn.sigma_nb_user_ready
309                    + load_15mn.sigma_nb_user_running)
310                  * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
311                  / load_15mn.sigma_nb_ticks;
312   sos_restore_IRQs(flags);
313 }
314 
315 
316 void sos_load_get_sload(sos_ui32_t * _load_1mn,
317                         sos_ui32_t * _load_5mn,
318                         sos_ui32_t * _load_15mn)
319 {
320   sos_ui32_t flags;
321 
322   if (load_1mn.sigma_nb_ticks < 1)
323     return;
324 
325   /* The "IDLE" thread is always either ready or running by definition */
326   SOS_ASSERT_FATAL(load_1mn.sigma_nb_kernel_ready
327                    + load_1mn.sigma_nb_kernel_running
328                    >= load_1mn.sigma_nb_ticks);
329 
330   /* Remove the IDLE thread from the load calculation */
331   sos_disable_IRQs(flags);
332   *_load_1mn  = ( load_1mn.sigma_nb_kernel_ready
333                   + load_1mn.sigma_nb_kernel_running
334                   - load_1mn.sigma_nb_ticks)
335                 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
336                 / load_1mn.sigma_nb_ticks;
337   *_load_5mn  = ( load_5mn.sigma_nb_kernel_ready
338                   + load_5mn.sigma_nb_kernel_running
339                   - load_5mn.sigma_nb_ticks)
340                 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
341                 / load_5mn.sigma_nb_ticks;
342   *_load_15mn  = ( load_15mn.sigma_nb_kernel_ready
343                    + load_15mn.sigma_nb_kernel_running
344                    - load_15mn.sigma_nb_ticks)
345                  * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
346                  / load_15mn.sigma_nb_ticks;
347   sos_restore_IRQs(flags);
348 }
349 
350 
351 void sos_load_get_uratio(sos_ui32_t * _load_1mn,
352                          sos_ui32_t * _load_5mn,
353                          sos_ui32_t * _load_15mn)
354 {
355   sos_ui32_t flags;
356 
357   if (load_1mn.sigma_nb_ticks < 1)
358     return;
359 
360   sos_disable_IRQs(flags);
361   *_load_1mn  = load_1mn.sigma_nb_user_running
362                 * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
363                 / load_1mn.sigma_nb_ticks;
364   *_load_5mn  = load_5mn.sigma_nb_user_running
365                 * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
366                 / load_5mn.sigma_nb_ticks;
367   *_load_15mn  = load_15mn.sigma_nb_user_running
368                  * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
369                  / load_15mn.sigma_nb_ticks;
370   sos_restore_IRQs(flags);
371 }
372 
373 
374 void sos_load_get_sratio(sos_ui32_t * _load_1mn,
375                          sos_ui32_t * _load_5mn,
376                          sos_ui32_t * _load_15mn)
377 {
378   sos_ui32_t flags;
379 
380   if (load_1mn.sigma_nb_ticks < 1)
381     return;
382 
383   /* Don't remove the CPU occupation ration of the IDLE thread
384      here... */
385   sos_disable_IRQs(flags);
386   *_load_1mn  = load_1mn.sigma_nb_kernel_running
387                 * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
388                 / load_1mn.sigma_nb_ticks;
389   *_load_5mn  = load_5mn.sigma_nb_kernel_running
390                 * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
391                 / load_5mn.sigma_nb_ticks;
392   *_load_15mn  = load_15mn.sigma_nb_kernel_running
393                  * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR
394                  / load_15mn.sigma_nb_ticks;
395   sos_restore_IRQs(flags);
396 }

source navigation ] diff markup ] identifier search ] general search ]