# 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 */ }