ftrias / TeensyThreads

MIT License
182 stars 26 forks source link

Way to determine CPU load percentage? #5

Open smachin1000 opened 7 years ago

smachin1000 commented 7 years ago

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.

ftrias commented 7 years ago

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.

smachin1000 commented 7 years ago

OK. Can you suggest a good way to measure the overhead of context switching? E.g. if I set the slice time to something line 100us, there surely must be some overhead in switching so frequently?

On Thu, Sep 28, 2017 at 5:16 PM, Fernando Trias notifications@github.com wrote:

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.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ftrias/TeensyThreads/issues/5#issuecomment-332997345, or mute the thread https://github.com/notifications/unsubscribe-auth/ABP3E-tGlB9ksMf97WqbjJy9kk3H7OZMks5snDb1gaJpZM4PoAs9 .

ftrias commented 7 years ago

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.

smachin1000 commented 7 years ago

Thanks for the detailed response, that all makes sense.

Is there a way to ask questions about the library without creating bug tickets? E.g. a forum, or Wiki FAQ?

On Fri, Sep 29, 2017 at 5:38 AM, Fernando Trias notifications@github.com wrote:

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.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ftrias/TeensyThreads/issues/5#issuecomment-333114985, or mute the thread https://github.com/notifications/unsubscribe-auth/ABP3E3vygUsKjzkI-95WFqiCFT6pMHdsks5snOTMgaJpZM4PoAs9 .

mjs513 commented 7 years ago

Typically been using the teensyThreads thread on the PRJC forum: https://forum.pjrc.com/threads/41504-Teensy-3-x-multithreading-library-first-release?highlight=teensythreads

8bitbunny commented 6 years ago

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 :)

8bitbunny commented 6 years ago

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 :)

mikaeltulldahl commented 4 years ago

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();
}