ftrias / TeensyThreads

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Way to determine CPU load percentage?

smachin1000 opened this issue · comments

Hi,

There a way I could calculate the instantaneous percentage CPU load on a Teensy board? E.g. I'd like to see how much % CPU is being used when the system is idle.

Hi! I don't think the Teensy has a concept of "idle". Unlike on a desktop or phone, the Teensy's CPU never goes to sleep or reduced speed. It is always doing something. Even "delay(x)" goes into a loop.

I haven't measured the exact time the context switch takes. It depends on many factors, including the speed you are running the CPU. But this overhead may or may make any difference. If your program does a lot of waiting around (for button clicks, sensor readings, etc), it may not make any difference at all; and in some cases, the multithreading means multiple threads can wait around simultaneously as opposed to sequentially and thus response time is improved. So you'll probably get a better idea by benchmarking your code under different scenarios.

commented

just to mention, it won't be that hard to implement if one knows what he is doing :)

let me explain the basic algo which i am working on for my bare low power system based on my modded teensythreads:

on top of main sketch:
a volatile isr count variable.
a increment isr (intervaltimer or other isr) at a pre defined frequency (100 cycles/second as basic example here)

timer function:
disable interrupts
increment timer
enable interrupts

setup function:
start of the timer, and passes the frequency to the threads lib
rest of startup code, and init threads needed
teensythreads:
simply has a buffer which checks how much of the cycles passed in contect switch compared to cycles per seconds passed at setup
normalizes that value to a percentage 
overwrites the existing buffer of the variable
if timer passed cycles in a second: reset timer variable
value can be read in a public accessible API function for monitoring each thread id

so if a thread took the time of less than one ISR increase: 0% load, 1 ISR increase: 1%, 2 ISR increases: 2%, ect.

also usefull to add the 'idle' time in a seperate value, making that able to be read by the API as well as idle time :)

this is basically what other RTOS' do :)

commented

cpumon

i simply got this working in less than 60 minutes of implementing it, and i am not the greatest coder :P (the dynamic cpu sleep pull request caused issues for a few days, i just didn't got it to work)

this is output from a teensy 3.6 running some (blink, print dynamic timed payload) threads in teensythreads at 24mhz f_cpu.

worth noting regarding teensythreads in general: just put threads to sleep at code intense places, as the running threads seems to block other threads in high payloads (if you have a payload that runs 300ms without thread sleeps inbetween, other threads can't execute in that timeframe).
this can be an issue with adc readings and periodic timers.
a solution for that problem would be to implement a intervaltimer to read adc data needed while the thread is blocked. or run a time critical piece of code upon request, regardless if the thread is executing :)

Here is one way to measure cpu load.
the idea is to spend all the unused time in the idle thread, where some pointless calculation is used to take some time.
I'm using teensy 3.5. if you use another one you will need to tune the "311" to get 100% free when nothing else is running.

#include <TeensyThreads.h>
volatile uint32_t idleCounter = 0;
int32_t millisSinceCPULoadUpdate = 0;
const int32_t cpuLoadUpdateRate = 5;  // sec
const int ledPin = 13;

void fooThread() {
  while (1) {
      digitalWrite(ledPin, HIGH);
      threads.delay(1000);
      digitalWrite(ledPin, LOW);
      threads.delay(1000);
  }
}

void idleThread() {
  while (1) {
    int32_t dt = (int32_t)millis() - millisSinceCPULoadUpdate;
    if (dt >= 1000 * cpuLoadUpdateRate) {
      Serial.print("free cpu: ");
      Serial.print(idleCounter / 100);
      Serial.println("%");
      idleCounter = 0;
      millisSinceCPULoadUpdate += dt;
    }

    // do some pointless heavy lifting to burn cpu cycles;
    for (volatile int i = 0; i < 311 * cpuLoadUpdateRate; i++) {
      volatile float a = 123;
      volatile float b = sqrtf(a);
      (void)b;  // to suppress [-Wunused-variable] warning
    }
    idleCounter++;
    threads.yield();
  }
}

void setup() {
  Serial.begin(115200);
  threads.addThread(fooThread);
  threads.addThread(idleThread);
}

void loop() {
  threads.yield();
}