Why my library is so slow?

Hi,
i made my first library, but after using it in my main project performance dropped A LOT. Is using classes that heavy for arduino or i have done something wrong?

I was using 10 standard millis timers and 13 comparisons like this:

if (previousValue != currentValue) {
 previousValue = currentValue;
 doSomething();
}

Then i used 23 objects and my lps counter* values droped from ~11 800 to ~70. //this values are true when touchscreen isn't active. Other functions sometimes drop this value to 10K. During drawing of tft its less then 10 lps.

(*every time loop is closed counter increases, after a second I print it on screen and change value to 0. It give me at least some information what parts of my code take the longest to execute.)

Library .cpp file:

#include "Tasks.h"
   

bool Tasks::timer(unsigned long timerInterval) {
	
if (  (millis() - previousTimer >= timerInterval || timerForcedReset) && run) {
    timerForcedReset = false;
    previousTimer = millis();
    return true;
  } else return false;

  
} //time

void Tasks::timerReset() {
  timerForcedReset = true;
}

bool Tasks::revise (int intValue) {

  if (	(previousIntValue != intValue || reviseForcedReset) && run) {
    reviseForcedReset = false;

    previousIntValue = intValue;
    return true;
  }
  else return false;
}

void Tasks::reviseReset() {
  reviseForcedReset = true;
}

.h file

#ifndef Tasks_H
#define Tasks_H

#include <Arduino.h>

  class Tasks {
    
    public: 
  
    Tasks(bool run = true) {
      this->run = run;
    }
    
    bool timer(unsigned long timerInterval);
    void timerReset();
    bool revise (int intValue);
    void reviseReset();
    #define FORBIT 0

  
    private:
  
    bool timerForcedReset;
    bool reviseForcedReset;
    unsigned long previousTimer;
    unsigned long timerInterval;
    int previousIntValue; 
	  bool run;

  };

#endif

I didn't change anything in my main project besides changing timers and checking if values are changed.

Others library for my arduino mega i don't think was that heavy, but.. i was using only ~10 objects before my liblary, now its over 30.
I still have over 5K of free SRAM memory during use (not during saving code to arduino) and over 80% free memory for sketch.

Is using objects/classes that heavy for arduino or i have done something wrong?

I was planning to move my project to ESP already, but i don't want to take with me buggy code that works only because other processor is faster.

Thanks in advance, u're better then any teacher i had ^^

The problem is likely in the code that you haven't posted.

Okay, i'll try to make some simpler example and post it here (my main code have over 3K lines, nobody want to read that).

I'll be back soon.

The answer is more complicated than I can simply describe as you need to dig into GCC and also consider you are not programming a PC with compute cores running in the giga-Hertz range.

The fastest coding is simply top ---> bottom within loop(). Calls to functions uses clock cycles to push the stack and pop the stack so the function can be instantiated which includes private variables being created & destroyed as the function terminates. C/C++ does this efficiently, but is does use clock cycles.

Object creation and destruction works similarly but as with functions, there are extra clock cycles required for instance creation and destruction. Efficiency can likely be gained by static class members:
https://www.tutorialspoint.com/cplusplus/cpp_static_members.htm

Use simple functions if possible; use a class only if sensible.
Classes often have methods, which are functions that are associated with a particular class, and do things associated with the thing that the class is - but if all you want is to do something, a function is all you need.

Memory Architectures | Memories of an Arduino | Adafruit Learning System

Shortly, u're right. Thanks.

I create blank document and add 20 'hand written' checks and then 20 objects one.

Loop per second counter dropped from 28K to 16K. It is ~twice much to calculate, it's sounds right.

It is impossible to say since we can't see either the previous code or the new "slower" code.

Not sure what you mean by "A LOT".
Using more structured constructs such as Classes can add some overhead vs doing things in line but it tends to be more incremental than a huge difference.
But the performance can also be increased if the use of higher level constructs allows implementing a better way of handling something like say a more efficient algorithm or the ability to time shift certain operations to better utilize the overall CPU cycles available by say reducing or eliminating busy delays.

If you had a significant change in performance/speed of something, or there is added latency in delay execution I would suspect you have fundamentally changed the way the code executes during your refactoring.
i.e. the code doesn't work the same way it used it vs having higher overhead of something like the use of a class.

You even said you changed the timers so perhaps the changes associated with that are not working the way you intended.

--- bill

post both codes

I wrote this sample sketch, and the performance looks very healthy to me, using 27 timers. A little over 38,000 lps on an Arduino Uno.

Chances are the problem is somewhere else...

//https://forum.arduino.cc/t/why-my-library-is-so-slow/1008123

#include "Tasks.h"

#define HOW_MANY 26
#define TIMER_INTERVAL 200
#define LOOP_COUNT_INTERVAL 5000

Tasks task[HOW_MANY];
Tasks loopCount;

unsigned long loopCounter;
unsigned long row=0;

void setup() {
  Serial.begin(115200);
  Serial.println("\nStarting");
  loopCounter = 0;
}

void loop() {
  loopCounter++;

  for (int i = 0; i < HOW_MANY; i++) {
    if (task[i].timer(TIMER_INTERVAL * (i + 1))) {
      Serial.print(char ('A' + i));
    }
    if (loopCount.timer(LOOP_COUNT_INTERVAL))  {
    	row++;
    	Serial.print("\n");
    	Serial.print(row);
    	Serial.print("\t");
    	Serial.print(millis());
        Serial.print("\tLoop count: ");
        Serial.print(loopCounter);
        Serial.print(": ");
        loopCounter = 0;
    }

  }
}


In 'loop per second counter' it's important to count it every second xd
Thanks, i'm trying to understand what gone wrong during implementing it to main program

It used most of my CPU cycles (i wrote about it). Now i know problem is in my main project - i will try to find it myself. If i fail i'll come back and post code

Thanks for help!

This is where having a logic analyzer can be helpful.
You can insert a small piece of code that toggles a pin(s) which adds very little overhead and use a logic analyzer to see the toggles
This allows you time various portions of the code and see where the overhead is.

You can purchase USB based logic analyzers on ebay starting at around $10 USD that is more than adequate for this as well being able to see all kinds of things happening on pins along with the ability to decode signals including things like i2c

--- bill

1 Like

I have one from long ago that cost 10x that, and access to a "real" one I could never personally justify even if I could afford it. This kind below I have gets quite a bit of use, with good free software available, Pulseview.

https://www.amazon.com/Comidox-Analyzer-Device-Channel-Arduino/dp/B07KW445DJ/ref=asc_df_B07KW445DJ

HTH

a7

I found my mistake! I was passing eeprom.read to my Int revise/update.

i didn't thought about debugging by toggling pin, at my level serialprints are enough. But i'll try to remember this for future!

Thanks for help

I was mainly referring to using the technique as a method of profiling the code vs debugging.
--- bill

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.