📄 calcload.c
字号:
/* Copyright (C) 2004 David Decotigny 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 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <hwcore/irq.h>#include <sos/kmalloc.h>#include <sos/assert.h>#include <sos/calcload.h>/** * Multiplicative factor to display digits after the decimal dot. The * higher the value, the higher the precision, but the higher the risk * that the value you get is incorrect (integer overflow). * * The CPU ratios will be correctly displayed as long as: * 2^32 > (900 * HZ * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR) * The "900" above means 900s because the load is computed over 15mn (900s). * HZ is the frequency of the timer tick because the load is updated * at each timer tick. * The "100" above is the multiplication factor to get the ratio value * between 0 and 100 (instead of 0-1). * * The maximum CPU sustainable load that will be correctly displayed * is given by the formula: * (2^32 - 1) / (900 * HZ * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR) * With HZ=100, these maximum sustainable loads are respectively * 47.721, 477.21 and 4772.1 with * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR being respectively 1000, 100 * and 10. * * Hence, among these formulaes, the most limitative one is that * concerning the CPU ratios (because of the "100" factor). Actually, * for HZ=100, the only correct value is 10. */#define SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR 10 /* 1/10 resolution *//** * To compute the load, at each clock tick we store the number of * threads ready in kernel/user mode, and the kind of the thread that * is executing (user or kernel mode): this is stored in * current_load_entry. We then compute the sum of these numbers over 3 * periods of time: 1 minute, 5 minutes, 15 minutes. This is the role * of the sliding windows data structures. A "sliding window" is only * the synthetic sum of these figures, not a real sliding window of * load_entries. At each timer tick and everytime the load is updated, * the computations are in O(1). * * All the sliding windows share the main "recorded_load" array of * load_entries for that; its role is to store the last 15mns of load * data, which encompasses the data for the 1mn, 5mn and 15mn sliding * windows. *//* Max number of seconds that we record (ie number of entries in recorded_loads) */#define NB_SECS 900/* An entry in the longest sliding window */struct load_entry{ sos_ui32_t nb_ticks; sos_ui32_t nb_user_running; sos_ui32_t nb_kernel_running; sos_ui32_t nb_user_ready; sos_ui32_t nb_kernel_ready;};struct load_entry current_load_entry;/* The longest sliding window */struct recorded_loads{ sos_ui32_t most_recent; sos_ui32_t max_entries; struct load_entry *load_entries;};#define LOAD_GET_ENTRY(loads,age) \ (&((loads).load_entries[( (loads).max_entries + (loads).most_recent - (age))\ % ((loads).max_entries)]))/* A sliding window, we manage one for each time interval */struct sliding_window{ sos_ui32_t max_entries; sos_ui32_t nb_entries; sos_ui32_t sigma_nb_ticks; sos_ui32_t sigma_nb_user_running; sos_ui32_t sigma_nb_kernel_running; sos_ui32_t sigma_nb_user_ready; sos_ui32_t sigma_nb_kernel_ready;};/* The main sliding window */static struct recorded_loads recorded_loads;/* The sliding windows for 3 tims intervals: 1min, 5min, 15min */static struct sliding_window load_1mn, load_5mn, load_15mn;/* Forward declaration */static struct sos_timeout_action calcload_timeout;static void calcload_routine(struct sos_timeout_action *a);static void _reinit_load_subsystem(){ memset(& recorded_loads, 0x0, sizeof(recorded_loads)); memset(& current_load_entry, 0x0, sizeof(struct load_entry)); memset(& load_1mn, 0x0, sizeof(load_1mn)); memset(& load_5mn, 0x0, sizeof(load_5mn)); memset(& load_15mn, 0x0, sizeof(load_15mn));}sos_ret_t sos_load_subsystem_setup(void){ struct sos_time period; _reinit_load_subsystem(); if (recorded_loads.load_entries) sos_kfree((sos_vaddr_t) recorded_loads.load_entries); _reinit_load_subsystem(); /* Allocate 900 entries to store 15mn of data (because 15minutes = 900s) */ recorded_loads.max_entries = NB_SECS; recorded_loads.load_entries = (struct load_entry*) sos_kmalloc(NB_SECS * sizeof(struct load_entry), 0); if (! recorded_loads.load_entries) { return -SOS_ENOMEM; } /* Compute the number of entries in each sliding window */ load_1mn.max_entries = 60; load_5mn.max_entries = 300; load_15mn.max_entries = 900; /* Program the load computation action */ sos_time_init_action(& calcload_timeout); period.sec = 1; period.nanosec = 0; return sos_time_register_action_relative(& calcload_timeout, & period, calcload_routine, NULL);}/* Shift the given sliding window to record the current_load_entry */static void update_sliding_window(struct sliding_window *w){ /* * Compute the value of the sum over the sliding window */ /* Take the new value into account */ w->sigma_nb_ticks += current_load_entry.nb_ticks; w->sigma_nb_user_running += current_load_entry.nb_user_running; w->sigma_nb_kernel_running += current_load_entry.nb_kernel_running; w->sigma_nb_user_ready += current_load_entry.nb_user_ready; w->sigma_nb_kernel_ready += current_load_entry.nb_kernel_ready; /* Remove the oldest entry, if it is going to be popped out of the sliding window */ if (w->nb_entries < w->max_entries) { w->nb_entries ++; } else { struct load_entry * oldest_entry; oldest_entry = LOAD_GET_ENTRY(recorded_loads, w->nb_entries - 1); w->sigma_nb_ticks -= oldest_entry->nb_ticks; w->sigma_nb_user_running -= oldest_entry->nb_user_running; w->sigma_nb_kernel_running -= oldest_entry->nb_kernel_running; w->sigma_nb_user_ready -= oldest_entry->nb_user_ready; w->sigma_nb_kernel_ready -= oldest_entry->nb_kernel_ready; }}/* The timeout action responsible for computing the CPU load */static void calcload_routine(struct sos_timeout_action *a){ struct load_entry * new_head; struct sos_time delay; if (! recorded_loads.load_entries) return; /* Update the sliding windows */ update_sliding_window(& load_1mn); update_sliding_window(& load_5mn); update_sliding_window(& load_15mn); /* Move the head of the list forward */ recorded_loads.most_recent = (recorded_loads.most_recent + 1) % recorded_loads.max_entries; /* Update the new head */ new_head = & recorded_loads.load_entries[recorded_loads.most_recent]; memcpy(new_head, & current_load_entry, sizeof(current_load_entry)); /* Reset the current load entry */ memset(& current_load_entry, 0x0, sizeof(current_load_entry)); /* Program next occurence of the action */ delay.sec = 1; delay.nanosec = 0; sos_time_register_action_relative(a, & delay, calcload_routine, NULL);}sos_ret_t sos_load_do_timer_tick(sos_bool_t cur_is_user, sos_ui32_t nb_user_ready, sos_ui32_t nb_kernel_ready){ sos_ui32_t flags; sos_disable_IRQs(flags); current_load_entry.nb_ticks ++; current_load_entry.nb_user_ready += nb_user_ready; current_load_entry.nb_kernel_ready += nb_kernel_ready; if (cur_is_user) current_load_entry.nb_user_running ++; else current_load_entry.nb_kernel_running ++; sos_restore_IRQs(flags); return SOS_OK;}void sos_load_to_string(char dest[11], sos_ui32_t load_value){ sos_bool_t print0 = FALSE; sos_ui32_t d;#define PUTCH(c) ({ *dest = (c); dest ++; }) for (d = 1000000000UL ; d > 0 ; d /= 10) { sos_ui32_t digit = (load_value / d) % 10; if (digit > 0) { PUTCH(digit + '0'); print0 = TRUE; } else if (print0) PUTCH('0'); if (d == SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR) { if (! print0) PUTCH('0'); PUTCH('.'); print0 = TRUE; } } *dest = '\0';}void sos_load_get_uload(sos_ui32_t * _load_1mn, sos_ui32_t * _load_5mn, sos_ui32_t * _load_15mn){ sos_ui32_t flags; if (load_1mn.sigma_nb_ticks < 1) return; sos_disable_IRQs(flags); *_load_1mn = ( load_1mn.sigma_nb_user_ready + load_1mn.sigma_nb_user_running) * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_1mn.sigma_nb_ticks; *_load_5mn = ( load_5mn.sigma_nb_user_ready + load_5mn.sigma_nb_user_running) * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_5mn.sigma_nb_ticks; *_load_15mn = ( load_15mn.sigma_nb_user_ready + load_15mn.sigma_nb_user_running) * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_15mn.sigma_nb_ticks; sos_restore_IRQs(flags);}void sos_load_get_sload(sos_ui32_t * _load_1mn, sos_ui32_t * _load_5mn, sos_ui32_t * _load_15mn){ sos_ui32_t flags; if (load_1mn.sigma_nb_ticks < 1) return; /* The "IDLE" thread is always either ready or running by definition */ SOS_ASSERT_FATAL(load_1mn.sigma_nb_kernel_ready + load_1mn.sigma_nb_kernel_running >= load_1mn.sigma_nb_ticks); /* Remove the IDLE thread from the load calculation */ sos_disable_IRQs(flags); *_load_1mn = ( load_1mn.sigma_nb_kernel_ready + load_1mn.sigma_nb_kernel_running - load_1mn.sigma_nb_ticks) * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_1mn.sigma_nb_ticks; *_load_5mn = ( load_5mn.sigma_nb_kernel_ready + load_5mn.sigma_nb_kernel_running - load_5mn.sigma_nb_ticks) * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_5mn.sigma_nb_ticks; *_load_15mn = ( load_15mn.sigma_nb_kernel_ready + load_15mn.sigma_nb_kernel_running - load_15mn.sigma_nb_ticks) * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_15mn.sigma_nb_ticks; sos_restore_IRQs(flags);}void sos_load_get_uratio(sos_ui32_t * _load_1mn, sos_ui32_t * _load_5mn, sos_ui32_t * _load_15mn){ sos_ui32_t flags; if (load_1mn.sigma_nb_ticks < 1) return; sos_disable_IRQs(flags); *_load_1mn = load_1mn.sigma_nb_user_running * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_1mn.sigma_nb_ticks; *_load_5mn = load_5mn.sigma_nb_user_running * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_5mn.sigma_nb_ticks; *_load_15mn = load_15mn.sigma_nb_user_running * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_15mn.sigma_nb_ticks; sos_restore_IRQs(flags);}void sos_load_get_sratio(sos_ui32_t * _load_1mn, sos_ui32_t * _load_5mn, sos_ui32_t * _load_15mn){ sos_ui32_t flags; if (load_1mn.sigma_nb_ticks < 1) return; /* Don't remove the CPU occupation ration of the IDLE thread here... */ sos_disable_IRQs(flags); *_load_1mn = load_1mn.sigma_nb_kernel_running * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_1mn.sigma_nb_ticks; *_load_5mn = load_5mn.sigma_nb_kernel_running * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_5mn.sigma_nb_ticks; *_load_15mn = load_15mn.sigma_nb_kernel_running * 100 * SOS_LOAD_DISPLAY_MULTIPLICATION_FACTOR / load_15mn.sigma_nb_ticks; sos_restore_IRQs(flags);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -