This is the mail archive of the ecos-discuss@sourceware.cygnus.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: load monitoring (on an ARM)


This is not as clean as it should be but ....

        Andrew

____________________________

Andrew Lunn
Research Engineer
Phone +41 62 889 52 97
Fax +41 62 889 52 90
Andrew.Lunn@ascom.ch

Ascom Systec Ltd.
Applicable Research & Technology
Gewerbepark
CH-5506 Maegenwil
Switzerland

www.ascom.com/art


/* This files provides a simple CPU load meter. All loads are returned
   as a percentage, ie 0-100. This is only a rough measure. */

/* This code is Copywrite ASCOM SYSTEC, Gewerberpark, Magenwil,
   Switzerland, 1999, 2000 etc. Fee free to use, modify, hack, but not
   sell for money. ASCOM Takes no responsiability for this code at all
   etc. 
#include <std/disclaimer.h>
*/

#include <cyg/kernel/kapi.h>
#include <cyg/hal/hal_arch.h>  /* Needed for the HAL_IDLE_THREAD_ACTIOM */
#include <assert.h>
#include "cpu_load.h"

/* Here we run the idle thread as a high priority thread for 0.1
   second and see how much the counter in the idle loop is
   incremented. This will only work is there are no other threads
   running at priority 1 and 2 */

static cyg_thread thread;
extern cyg_uint32 idle_thread_loops;
char idle_stack[CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE];

// -------------------------------------------------------------------------
// Idle thread code. This is a cut and paste from thread.cxx. Some day i will
// work out how to call the real idle thread 

void
idle_thread_main( CYG_ADDRESS data )
{
  //    CYG_REPORT_FUNCTION();

    for(;;)
    {
        idle_thread_loops++;

        HAL_IDLE_THREAD_ACTION(idle_thread_loops);

#if 0
        // For testing, it is useful to be able to fake
        // clock interrupts in the idle thread.
        
        Cyg_Clock::real_time_clock->tick();
#endif
#ifdef CYGIMP_IDLE_THREAD_YIELD
        // In single priority and non-preemptive systems,
        // the idle thread should yield repeatedly to
        // other threads.
        Cyg_Thread::yield();
#endif
    }
}
// -------------------------------------------------------------------------

/* 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. Well thats the theory */

void static 
alarm_func(cyg_handle_t alarm,cyg_addrword_t data) { 
  cyg_handle_t idleH = (cyg_handle_t) data;
  cyg_thread_suspend(idleH); 
}

void 
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_ASSERT(idleH != cyg_thread_self(),"Scheduler is broken!");

  cyg_thread_create(1,
		    idle_thread_main,
		    0,
		    "Calibration idle thread",
		    idle_stack,
		    CYGNUM_KERNEL_THREADS_IDLE_STACK_SIZE,
		    &idleH,
		    &thread);

  CYG_ASSERT(idleH != cyg_thread_self(),"Scheduler is broken!");

  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 ! */
  CYG_ASSERT(idleH != cyg_thread_self(),"Scheduler is broken!");
  
  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_ASSERT(idleH != cyg_thread_self(),"Scheduler is broken!");
  cyg_thread_kill(idleH);
}

  static uint32 last_time = 0;
  static int last_frame_count =0;
  static int count =0;

static void 
cpuload_alarm_func(cyg_handle_t alarm,cyg_addrword_t data) { 
  cpuload_t * cpuload = (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->life++;
  cpuload->last_idle_loops = idle_loops_now;
  
}


void 
cpuload_create(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;
}

void 
cpuload_delete(cyg_handle_t handle) {
  cpuload_t * cpuload = (cpuload_t *) handle;

  cyg_alarm_delete(cpuload->alarmH);
}  

void
cpuload_get(cyg_handle_t handle,
	    cyg_uint32 *average_point1s, 	    
	    cyg_uint32 *average_1s, 	    
	    cyg_uint32 *average_10s) {

  cpuload_t * cpuload = (cpuload_t *) handle;
  *average_point1s = cpuload->average_point1s;
  *average_1s = cpuload->average_1s/10;
  *average_10s = cpuload->average_10s/100;
}

------------------------
* cpuload.h - functions that give a rough estimate of the cpu load. */
#ifndef CPU_LOAD_H
#define CPU_LOAD_H

#include <cyg/kernel/kapi.h>

typedef struct 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_uint32 life;
} cpuload_t;

void cpuload_calibrate(cyg_uint32  *calibration);
void cpuload_create(cpuload_t *cpuload,
                    cyg_uint32 colibrate,
                    cyg_handle_t *handle);
void cpuload_delete(cyg_handle_t handle);
void cpuload_get(cyg_handle_t handle,
                 cyg_uint32 *average_point1s,
                 cyg_uint32 *average_1s,
                 cyg_uint32 *average_10s);

#endif /* CPU_LOAD_H */









Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]