⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calcload.c

📁 Simple Operating Systems (简称SOS)是一个可以运行在X86平台上(包括QEMU
💻 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 + -