speed4.cpp

This sketch demonstrates a way to perform dynamic CPU throttling by combining the control offered by the Processor object with the monitoring offered by the Profile object.

It 'does work', piece by piece, in an alarm handler, while another alarm monitors the Profile. When the time spent in alarm handlers becomes too high or low, the Processor is sped up or slowed down accordingly, if possible.

An interaction with this sketch might look like:

w300
Ln 16.424 Workload=300
Ln 17.060 Load: 22%, speed changed to: 36MHz
Ln 18.070 Load: 25%, speed changed to: 24MHz
w800
Ln 22.922 Workload=800
Ln 24.098 Load: 95%, speed changed to: 36MHz
Ln 25.108 Load: 67%, speed changed to: 48MHz
w10
Ln 30.467 Workload=10
Ln 31.116 Load: 20%, speed changed to: 36MHz
Ln 32.126 Load:  0%, speed changed to: 24MHz
Ln 33.146 Load:  1%, speed changed to: 12MHz
w1200
Ln 39.719 Workload=1200
Ln 41.188 Load: 92%, speed changed to: 24MHz
Ln 42.198 Load: 95%, speed changed to: 36MHz
Ln 43.213 Load: 96%, speed changed to: 48MHz
Ln 44.225 Load: 82%, speed changed to: 60MHz
Ln 45.230 Load: 72%, speed changed to: 72MHz

where we send 'w' packets to alter the workload at various times, provoking dynamic speed changes when the alarm handling load falls outside the 33% - 66% band.

u32 workLoad = 500;             // Loops per workloadHandler call

void setWorkload(u8 * packet) {
  u32 arg;
  if (packetScanf(packet,"w%d\n",&arg) == 3 && arg < 2000)
    workLoad = arg; 
  logNormal("Workload=%d\n", workLoad);
}

void workloadHandler(u32 when) { // Alarm handler for 'doing work'
  u32 sum = 0;
  for (u32 i = 0; i < workLoad; ++i)   // Work, for us, is just
    sum += random(1000);               // adding up random numbers
  ledSet(BODY_RGB_BLUE_PIN, sum&1);    // and maybe lighting an LED..
  when += 10;                          // Do work every 10ms
  if (IS_EARLIER(when,millis())) when = millis(); // Or ASAP if we're behind
  Alarms.set(Alarms.currentAlarmNumber(),when); // Reschedule
}

void processorMonitor(u32 when) { // Alarm handler for controlling processor speed
  u32 load = Profile.getPPM(TICKER_ALARM_HANDLER)/10000; // Get alarm time, as a percent
  bool lowLoad = load < 33;     // Say under 33% is underloaded
  bool highLoad = load > 66;    // Say over 66% is overloaded

  ledSet(BODY_RGB_RED_PIN,highLoad);   // Display overload condition
  ledSet(BODY_RGB_GREEN_PIN,lowLoad);  // Display underload condition

  u32 speedCode = Processor.getCode(); // Find out how fast we're running now
  if (highLoad && speedCode < Processor.getCodeMax()) // If need and have more..
    ++speedCode;                // More coal to the furnace!  Shovel!
  else if (lowLoad && speedCode > Processor.getCodeMin()) // If need and have less..
    --speedCode;                // Whoa, nellie..

  if (speedCode != Processor.getCode()) {
    Processor.setCode(speedCode);
    logNormal("Load: %2d%%, speed changed to: %dMHz\n",load,Processor.getMHz());
  }

  Profile.begin();                    // Reset statistics gathering
  Alarms.set(Alarms.currentAlarmNumber(),millis()+1000); // Do monitoring about 1Hz
}

void setup() {
  Profile.begin();              // Start profiling
  Body.reflex('w',setWorkload); // Create reflex
  Alarms.set(Alarms.create(workloadHandler),millis());  // Alarm to generate work
  Alarms.set(Alarms.create(processorMonitor),millis()); // Alarm to monitor load
}

void loop() { /* Nothing to do */ }

Generated on Fri Apr 22 06:54:11 2011 for SFB by doxygen 1.5.9