changeset 301:7de36227e601

* Created a new package with my CPU load measurement code which has been sitting in the ecos-discuss archive for 2 and a bit years.
author asl
date Mon, 19 Aug 2002 14:32:06 +0000
parents 58c748750ca6
children 6c5a25ce39f6
files packages/services/cpuload/current/ChangeLog packages/services/cpuload/current/cdl/cpuload.cdl packages/services/cpuload/current/doc/cpuload.sgml packages/services/cpuload/current/include/cpuload.h packages/services/cpuload/current/src/cpuload.cxx packages/services/cpuload/current/tests/cpuload.c
diffstat 6 files changed, 693 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/services/cpuload/current/ChangeLog
@@ -0,0 +1,40 @@
+2002-08-15  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* Created a new package with my CPU load measurement code which
+	  has been sitting in the ecos-discuss archive for 2 and a bit
+	  years.
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Andrew Lunn
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/services/cpuload/current/cdl/cpuload.cdl
@@ -0,0 +1,72 @@
+# ====================================================================
+#
+#      cpuload.cdl
+#
+#      cpu load measurements
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2002 Andrew Lunn
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      Andrew Lunn
+# Original data:  Andrew Lunn
+# Contributors:
+# Date:           2002-08-12
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_CPULOAD {
+    display       "Measure the current CPU load"
+    requires      CYGPKG_KERNEL
+    requires      !CYGPKG_KERNEL_SMP_SUPPORT
+    include_dir   cyg/cpuload
+    
+    compile cpuload.cxx
+    description "
+       This package measures the CPU load over the last 100ms, 1second 
+       and 10 second. All loads are returned as a percentage, ie 0-100.
+       This is only a rough measure. Any clever power management, sleep 
+       modes etc, will cause these results to be wrong."
+
+    cdl_option CYGPKG_CPULOAD_TESTS {
+        display "POSIX CRC tests"
+        flavor  data   
+        no_define      
+        calculated { "tests/cpuload.c" }
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/packages/services/cpuload/current/doc/cpuload.sgml
@@ -0,0 +1,149 @@
+<PART ID="services-cpuload">
+<TITLE>CPU load measurements</TITLE>
+<PARTINTRO>
+<PARA>
+The cpuload package provides a way to estimate the cpuload. It gives
+an estimated percentage load for the last 100 milliseconds, 1 second
+and 10 seconds.
+</PARA>
+</PARTINTRO>
+<CHAPTER id="cpuload-functions">
+<TITLE>CPU Load Measurements</TITLE>
+<SECT1 id="services-cpuload-api">
+<TITLE>CPU Load API</TITLE>
+<para>
+The package allows the CPU load to be estimated. The measurement code
+must first be calibrated to the target it is running on. Once this
+has been performed the measurement process can be started. This is a
+continuous process, so always providing the most up to data
+measurements. The process can be stopped at any time if required. Once
+the process is active, the results can be retrieved.
+</para>
+<para>
+Note that if the target/processor performs any power saving actions,
+such as reducing the clock speed, or halting until the next interrupt
+etc, these will interfere with the CPU load measurement. Under these
+conditions the measurement results are undefined. The synthetic target
+is one such system. See the implementation details at the foot of this
+page for further information.  </para>
+<para>
+SMP systems are not supported, only uniprocessor system.
+</para> 
+<para> The API for load measuring functions can be
+found in the file <filename>cyg/cpuload/cpuload.h</filename>.
+</para>
+<sect2 id="services-cpuload-api-cyg-cpuload-calibrate">
+<title>cyg_cpuload_calibrate</title>
+<para>
+This function is used to calibrate the cpu load measurement code. It
+makes a measurement to determine the CPU properties while idle.
+</para>
+<programlisting>
+void cyg_cpuload_calibrate(cyg_uint32  *calibration);
+</programlisting>
+<para>
+The function returns the calibration value at the location pointed to
+by <parameter>calibration</parameter>.
+</para>
+<para>
+This function is quite unusual. For it to work correctly a few
+conditions must be met. The function makes use of the two highest
+thread priorities. No other threads must be using these priorities
+while the function is being used. The kernel scheduler must be started
+and not disabled. The function takes 100ms to complete during which
+time no other threads will be run.
+<para>
+</sect2>
+<sect2 id="services-cpuload-api-cyg-cpuload-create">
+<title>cyg_cpuload_create</title>
+<para>
+This function starts the CPU load measurments.
+</para>
+<programlisting>
+void cyg_cpuload_create(cyg_cpuload_t *cpuload, 
+                        cyg_uint32 calibrate,
+                        cyg_handle_t *handle);
+</programlisting>
+<para>
+The measurement process is started and a handle to it is returned in
+<parameter>*handle</parameter>. This handle is used to access the
+results and the stop the measurement process. </para>
+</sect2>
+
+<sect2 id="services-cpuload-api-cyg-cpuload-delete">
+<title>cyg_cpuload_delete</title>
+<para>
+This function stops the measurement process. 
+</para>
+<programlisting>
+void cyg_cpuload_delete(cyg_handle_t handle);
+</programlisting>
+<para>
+<parameter>handle</parameter> should be the value returned by the create function.</para>
+</sect2>
+
+<sect2 id="services-cpuload-api-cyg-cpuload-get">
+<title>cyg_cpuload_get</title>
+<para>
+This function returns the latest measurements.
+</para>
+<programlisting>
+void cyg_cpuload_get(cyg_handle_t handle,
+		 cyg_uint32 *average_point1s, 	    
+		 cyg_uint32 *average_1s, 	    
+		 cyg_uint32 *average_10s);
+</programlisting>
+<para>
+<parameter>handle</parameter> should be the value returned by the
+create function. The load measurements for the last 100ms, 1s and 10s
+are returned in
+<parameter>*average_point1s</parameter>,<parameter>*average_1s</parameter>
+and <parameter>*average_10s</parameter> respectively.
+</para>
+</sect2>
+<sect2 id="services-cpuload-api-implementation">
+<title>Implementation details</title>
+<para>
+This section gives a few details of how the measurements are
+made. This should help to understand what the results mean.
+</para>
+<para>
+When there are no other threads runnable, eCos will execute the idle
+thread. This thread is always runnable and uses the lowest thread
+priority. The idle thread does little. It is an endless loop which
+increments the variable, <literal>idle_thread_loops</literal> and
+executes the macro <literal>HAL_IDLE_THREAD_ACTION</literal>. The cpu
+load measurement code makes use of the variable. It periodically
+examines the value of the variable and sees how much it has
+changed. The idler the system, the more it will have incremented. From
+this it is simple to determine the load of the system.
+</para>
+<para>
+The function <literal>cyg_cpuload_calibrate</literal> executes the
+idle thread for 100ms to determine how much
+<literal>idle_thread_loops</literal> is incremented on a system idle
+for 100ms. <literal>cyg_cpuload_create</literal> starts an alarm which
+every 100ms calls an alarm function. This function looks at the
+difference in <literal>idle_thread_loops</literal> since the last
+invocation of the alarm function and so calculated how idle or busy
+the system has been. The structure <literal>cyg_cpuload</literal> is
+updated during the alarm functions with the new results.  The 100ms
+result is simply the result from the last measurement period. A simple
+filter is used to average the load over a period of time, namely 1s
+and 10s. Due to rounding errors, the 1s and 10s value will probably
+never reach 100% on a fully loaded system, but 99% is often seen.
+</para>
+<para>
+As stated above, clever power management code will interfere with
+these measurements. The basic assumption is that the idle thread will
+be executed un-hindered and under the same conditions as when the
+calibration function was executed. If the CPU clock rate is reduced,
+the idle thread counter will be incremented less and so the CPU load
+measurements will give values too high. If the CPU is halted entirely,
+100% cpu load will be measured.
+<para>
+</sect2>
+</SECT1>
+</CHAPTER>
+</PART>
+
new file mode 100644
--- /dev/null
+++ b/packages/services/cpuload/current/include/cpuload.h
@@ -0,0 +1,94 @@
+//==========================================================================
+//
+//      cpuload.h
+//
+//      Interface for the cpuload code.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Andrew Lunn
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2002-08-12
+// Purpose:      
+// Description:  
+//      API for the cpuload measurement code
+//        
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef _SERVICES_CPULOAD_CPULOAD_H
+#define _SERVICES_CPULOAD_CPULOAD_H
+
+#ifdef __cplusplus
+externC 
+{
+#endif  
+
+typedef struct cyg_cpuload_s {
+  cyg_alarm alarm_s;
+  cyg_handle_t alarmH;
+  cyg_uint32 last_idle_loops;
+  cyg_uint32 average_point1s;
+  cyg_uint32 average_1s;
+  cyg_uint32 average_10s;
+  cyg_uint32 calibration;
+} cyg_cpuload_t;
+
+/* Calibrate the CPU load measurement code */
+void cyg_cpuload_calibrate(cyg_uint32  *calibration);
+
+/* Create a measurement object and start the measurements */
+void cyg_cpuload_create(cyg_cpuload_t *cpuload, 
+                        cyg_uint32 calibrate,
+                        cyg_handle_t *handle);
+
+/* Stop the measurements so the object can be freed */
+void cyg_cpuload_delete(cyg_handle_t handle);
+
+/* Get the current CPU load */
+void cyg_cpuload_get(cyg_handle_t handle,
+		 cyg_uint32 *average_point1s, 	    
+		 cyg_uint32 *average_1s, 	    
+		 cyg_uint32 *average_10s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SERVICES_CPULOAD_CPULOAD_H */
new file mode 100644
--- /dev/null
+++ b/packages/services/cpuload/current/src/cpuload.cxx
@@ -0,0 +1,206 @@
+//==========================================================================
+//
+//      cpuload.cxx
+//
+//      Estimate the current CPU load.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    Andrew Lunn
+// Contributors: Andrew Lunn
+// Date:         2002-08-12
+// Purpose:      
+// Description:  
+//    This provides a simple CPU load meter. All loads are returned
+//    as a percentage, ie 0-100. This is only a rough measure. Any clever
+//    power management, sleep modes etc, will cause these results to be
+//    wrong.
+//              
+// This code is part of eCos (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <cyg/kernel/kapi.h>
+#include <cyg/hal/hal_arch.h> 
+#include <cyg/cpuload/cpuload.h>
+
+/* Here we run the idle thread as a high priority thread for 0.1
+   second.  We see how much the counter in the idle loop is
+   incremented. This will only work if there are no other threads
+   running at priority 1 and 2 */
+
+static cyg_thread thread;
+externC cyg_uint32 idle_thread_loops;
+char idle_stack[CYGNUM_HAL_STACK_SIZE_MINIMUM];
+
+extern void idle_thread_main( CYG_ADDRESS data );
+
+// -------------------------------------------------------------------------
+/* We are playing ping-pong with the cpuload_calibrate function and
+   the idle thread. First cpuload_calibrate runs. Next the idle
+   thread, then this alarm function and then back to the
+   cpuload_calibrate function. */
+
+void static 
+alarm_func(cyg_handle_t alarm,cyg_addrword_t data) { 
+  cyg_handle_t idleH = (cyg_handle_t) data;
+  cyg_thread_suspend(idleH); 
+}
+
+
+/* Calibrate the cpuload measurements.*/
+externC void 
+cyg_cpuload_calibrate(cyg_uint32  *calibration) {
+  cyg_handle_t counter;
+  cyg_alarm alarm_s;
+  cyg_handle_t alarmH;
+  cyg_uint32 idle_loops_start;  
+  cyg_handle_t idleH;
+  cyg_priority_t old_priority;
+  
+  cyg_thread_create(1,
+		    idle_thread_main,
+		    0,
+		    "Calibration idle thread",
+		    idle_stack,
+		    sizeof(idle_stack),
+		    &idleH,
+		    &thread);
+  
+  cyg_clock_to_counter(cyg_real_time_clock(),&counter);
+  cyg_alarm_create(counter,alarm_func,(cyg_addrword_t)idleH,&alarmH,&alarm_s);
+  
+  cyg_alarm_initialize(alarmH,cyg_current_time()+10,0);
+  cyg_alarm_enable(alarmH);
+  
+  idle_loops_start = idle_thread_loops;
+  
+  /* Dont be decieved, remember this is a multithreaded system ! */
+  old_priority = cyg_thread_get_priority(cyg_thread_self());
+  cyg_thread_set_priority(cyg_thread_self(),2);
+  cyg_thread_resume(idleH);
+  cyg_thread_set_priority(cyg_thread_self(),old_priority);
+  
+  *calibration = idle_thread_loops - idle_loops_start;
+  cyg_alarm_delete(alarmH);
+  cyg_thread_kill(idleH);
+  cyg_thread_delete(idleH);
+}
+
+static void 
+cpuload_alarm_func(cyg_handle_t alarm,cyg_addrword_t data) { 
+  cyg_cpuload_t * cpuload = (cyg_cpuload_t *)data;
+  cyg_uint32 idle_loops_now = idle_thread_loops;
+  cyg_uint32 idle_loops;
+  cyg_uint32 load;
+  
+  if (idle_loops_now >= cpuload->last_idle_loops) {
+    idle_loops = idle_loops_now - cpuload->last_idle_loops;
+  } else {
+    idle_loops = ~0 - (cpuload->last_idle_loops - idle_loops_now);
+  }
+  
+  /* We need 64 bit arithmatic to prevent wrap around */ 
+  load = (cyg_uint32) (((cyg_uint64) idle_loops * (cyg_uint64)100) / 
+		       (cyg_uint64)cpuload->calibration);
+  if (load > 100) {
+    load = 100;
+  }
+  load = 100 - load;
+  
+  cpuload->average_point1s = load;
+  cpuload->average_1s = load + ((cpuload->average_1s * 90)/100);
+  cpuload->average_10s = load + ((cpuload->average_10s * 99)/100);
+  cpuload->last_idle_loops = idle_loops_now;
+}
+
+/* Create a CPU load measurements object and start the
+   measurements. */
+externC void 
+cyg_cpuload_create(cyg_cpuload_t *cpuload,
+                   cyg_uint32 calibration, 
+                   cyg_handle_t *handle) 
+{
+  cyg_handle_t counter;
+  
+  cpuload->average_point1s = 0;
+  cpuload->average_1s = 0;
+  cpuload->average_10s = 0;
+  cpuload->calibration = calibration;
+  cpuload->last_idle_loops = idle_thread_loops;
+
+  cyg_clock_to_counter(cyg_real_time_clock(),&counter);
+  cyg_alarm_create(counter,
+		   cpuload_alarm_func,
+		   (cyg_addrword_t)cpuload,
+		   &cpuload->alarmH,
+		   &cpuload->alarm_s);
+
+  cyg_alarm_initialize(cpuload->alarmH,cyg_current_time()+10,10);
+  cyg_alarm_enable(cpuload->alarmH);
+  
+  *handle = (cyg_handle_t) cpuload;
+}
+
+/* Stop measurements of the cpuload. The cyg_cpuload_t object can then
+   be freed. */
+externC void 
+cyg_cpuload_delete(cyg_handle_t handle) {
+  cyg_cpuload_t * cpuload = (cyg_cpuload_t *) handle;
+  
+  cyg_alarm_delete(cpuload->alarmH);
+}  
+
+/* Return the cpuload for the last 100ms, 1seconds and 10 second */
+externC void
+cyg_cpuload_get(cyg_handle_t handle,
+                cyg_uint32 *average_point1s, 	    
+                cyg_uint32 *average_1s, 	    
+                cyg_uint32 *average_10s) {
+
+  cyg_cpuload_t * cpuload = (cyg_cpuload_t *) handle;
+  *average_point1s = cpuload->average_point1s;
+  *average_1s = cpuload->average_1s/10;
+  *average_10s = cpuload->average_10s/100;
+}
+
+
+
+
new file mode 100644
--- /dev/null
+++ b/packages/services/cpuload/current/tests/cpuload.c
@@ -0,0 +1,132 @@
+//=================================================================
+//
+//        cpuload.c
+//
+//        test case for the cpuload code.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2002 Andrew Lunn
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     asl
+// Contributors:  asl
+// Date:          2002-08-06
+// Description:   Tests the calculation code
+//####DESCRIPTIONEND####
+
+#include <cyg/hal/hal_arch.h>
+#include <cyg/kernel/kapi.h>
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+#include <cyg/cpuload/cpuload.h>
+
+void
+do_test(cyg_addrword_t data) {
+  cyg_uint32 calibration;
+  cyg_cpuload_t cpuload;
+  cyg_handle_t handle;
+  cyg_uint32 average_point1s;
+  cyg_uint32 average_1s;
+  cyg_uint32 average_10s;
+  cyg_uint32 i,j;
+  
+  CYG_TEST_INFO("About to calibrate cpuload");
+  
+  cyg_cpuload_calibrate(&calibration);
+  
+  CYG_TEST_INFO("Performing 100% load test");
+  
+  cyg_cpuload_create(&cpuload,calibration,&handle);
+  
+  /* Busy loop doing useless work. This will cause the cpu load to be
+     100%. After all these iterations, check the measured load really
+     is 100%. */
+
+  for (i=250; i--; ) {
+    for (j=calibration*10; j-- ; ) 
+      ;
+    cyg_cpuload_get(handle,&average_point1s,&average_1s,&average_10s);
+    /* diag_printf("%d %d %d\n",average_point1s,average_1s,average_10s);*/
+  }
+
+  /* Rounding errors mean it will probably never reach 100% */
+  if ((average_point1s == 100) &&
+      (average_1s >= 99) && (average_1s <=100) &&
+      (average_10s >= 98) && (average_10s <= 100))
+    CYG_TEST_PASS("100% load o.k.");
+  else {
+    CYG_TEST_FAIL("100% load");
+  }
+  
+  /* Sleeping doing nothing. This will cause the cpuload to be
+     0%. After all these iterations, check the measured load really is
+     0%. */
+  CYG_TEST_INFO("Performing 0% load test");
+  for (i=350; i-- ; ) {
+    cyg_thread_delay(10);
+    cyg_cpuload_get(handle,&average_point1s,&average_1s,&average_10s);
+    /* diag_printf("%d %d %d\n",average_point1s,average_1s,average_10s);*/
+  }
+  
+  if ((average_point1s == 0) &&
+      (average_1s == 0) &&
+      (average_10s >= 0) && (average_10s <= 2))
+    CYG_TEST_PASS_FINISH("0% load o.k.");
+  else {
+    CYG_TEST_FAIL_FINISH("0% load");
+  }
+}
+
+
+externC void
+cyg_start(void) {
+
+#ifdef CYGPKG_HAL_SYNTH
+
+  CYG_TEST_NA("Not applicable to Synth target");
+#else
+  static char stack[CYGNUM_HAL_STACK_SIZE_MINIMUM];
+  static cyg_handle_t handle;
+  static cyg_thread thread;
+  
+  CYG_TEST_INIT();
+  
+  cyg_thread_create(4,do_test,0,"cpuload",
+                    stack,sizeof(stack),&handle,&thread);
+  cyg_thread_resume(handle);
+  
+  cyg_scheduler_start();
+#endif
+}