lonas
March 16, 2016, 9:59pm
1
Hi,
why when I'm including library dynamic memory is being used ?
I'm not creating instance of object yet - just using #include
I'm making a test where I comment out include library sketch is using 44% of ram - when I want to use lib it takes 64%
Shouldn't ram be reserved when I will declare object ?
system
March 16, 2016, 10:01pm
2
If only we could see some proof, and re-create the experiment {sigh}
DrAzzy
March 16, 2016, 10:01pm
3
What library?
Where is the code that causes this behavior?
lonas
March 16, 2016, 10:05pm
4
These are all libraries which I wrote - but here is quick example:
//#include <Keypad.h>
//#include <Alarm.h>
//#include <AlarmKeypad.h>
//#include <AlarmSettings.h>
//#include <TextReceiver.h>
//#include <TextSender.h>
//#include <Notification.h>
//#include <NotificationPublisher.h>
result : Global variables use 3,656 bytes (44%) of dynamic memory, leaving 4,536 bytes for local variables. Maximum is 8,192 bytes.
lets uncomment
#include <Alarm.h>
and result is
Global variables use 5,260 bytes (64%) of dynamic memory, leaving 2,932 bytes for local variables. Maximum is 8,192 bytes.
Is there something what I could do wrong in library definition what cause that behavior ?
lonas
March 16, 2016, 10:23pm
5
And most interesting thing is:
why even when I comment almost all content of Alarm h and cpp it still showing usage like 62% so just 2 % less.
But when completely remove alarm.h from import its back to 44% of usage
lonas:
And most interesting thing is:
why even when I comment almost all content of Alarm h and cpp it still showing usage like 62% so just 2 % less.
But when completely remove alarm.h from import its back to 44% of usage
You can't expect any help here if you don't show your library files.
Shouldn't ram be reserved when I will declare object ?
Only ram for that instance of the object is allocated when the instance is created. The class may require other data space.
Mark
lonas
March 16, 2016, 10:45pm
8
I had all classes related with Alarm under one package/directory - when I have moved each class to separate folders then commented code in alarm class showed me again 44% usage.
Here is some next test:
I'm importing just Alarm.h
In alarm class all I do is import move sensor class which giving me usage from 44 to 46%
#ifndef MoveSensor_h
#define MoveSensor_h
#include <Arduino.h>
#include <CommonConfiguration.h>
#include <MemoryVariables.h>
class MoveSensor
{
public:
MoveSensor(byte arduinoId, byte pin, byte actionId, byte actionTypeId = LOCAL_ACTION, byte floorId = GROUND_FLOOR, byte enabled = LOW);
void init();
byte getArduinoId();
byte getActionId();
bool isGroundFloor();
bool isFloor();
bool isMoveDetected();
bool isAlarmMoveDetected();
byte getActionTypeId();
void setEnabled(byte state);
private:
MemoryVariables memoryVariables;
byte arduinoId;
byte pin;
byte actionId;
byte actionTypeId;
byte floorId;
byte enabled;
byte lastAlarmStateDetected = 0;
word highAlarmStateTime = 0;
byte lastStateDetected = 0;
long changeTime = 0;
int movementFloodCounter = 0;
};
#endif
when I comment out from move sensor #include <MemoryVariables.h>
then usage is 42%
I dont know what is going on here...
In the spirit of "teaching you how to fish," there is a utility that you can use to create a map file which will show you what variables are being assigned to your memory.
Go to your "Arduino\hardware\tools\avr\bin" directory and find "avr-objdump.exe".
Go to the temporary directory when Arduino builds your code. It will be in a subdirectory created in "C:\Users\username\AppData\Local\Temp" that contains both "build" and ".tmp". You're going to want to find the .elf file in this directory.
Type the command "avr-objdump.exe -t elf_file_name.elf >> map_file_name.map"
If you create map files with your library not included, included, partially commented out, etc you can then compare them to see what additional memory was used in each case. If you don't already use a code-compare tool I recommend downloading one immediately (WinMerge is free, small, and very popular).
Steps 1-3 can get pretty annoying to do manually so I made a python script to do it for me. Here it is if you know how to run python scripts:
import os, subprocess
def sorted_ls(path):
mtime = lambda f: os.stat(os.path.join(path, f)).st_mtime
return list(sorted(os.listdir(path), key=mtime))
home_temp_dir = os.path.expanduser("~") + os.sep + 'AppData' + os.sep + 'Local' + os.sep + 'Temp'
last_build_dir = ''
for dir_item in reversed(sorted_ls(home_temp_dir)):
if((dir_item.find('build') >= 0 ) and (dir_item.find('.tmp') >= 0) ) :
last_build_dir = dir_item
break
if last_build_dir != '' :
elf_filename = ''
for dir_item in reversed(sorted_ls(home_temp_dir + os.sep + last_build_dir)):
if(dir_item.find('.elf') >= 0) :
elf_filename = dir_item
break
if elf_filename != '' :
print last_build_dir
print elf_filename
subprocess.call('avr-objdump.exe' + ' -S -s ' + home_temp_dir + os.sep + last_build_dir + os.sep + elf_filename + ' > ' + elf_filename[0:-3] + 'lst', shell=True)
subprocess.call('avr-objdump.exe' + ' -t ' + home_temp_dir + os.sep + last_build_dir + os.sep + elf_filename + ' > ' + elf_filename[0:-3] + 'map', shell=True)
lonas
March 16, 2016, 10:54pm
10
Is there any linux version for that what You mentioned ?
lonas
March 16, 2016, 10:59pm
11
Each library which I will comment out makes more memory space
comment out // #include <AlarmSettings.h> from Alarm.h makes 4% of space difference
Here is AlarmSettings.h
#ifndef AlarmSettings_h
#define AlarmSettings_h
#include <Arduino.h>
#include <EEPROM.h>
#include <MemoryVariables.h>
#include <Notification.h>
#include <Action.h>
#include <OpenWindowDetector.h>
class AlarmSettings
{
public:
void initWith(Notification *notification, Action *alarmSetting);
void addOpenWindowDetector(OpenWindowDetector *openWindowDetector);
void handle();
bool processSetting(String setting);
bool isAlarmArmed();
void armAlarm();
void disarmAlarm();
bool isGroundAlarmArmed();
void armGroundAlarm();
void disArmGroundAlarm();
bool isFloorAlarmArmed();
void armFloorAlarm();
void disArmFloorAlarm();
bool isAlarmFreezed();
void longTemporaryDisarmAlarm();
void shortTemporaryDisarmAlarm();
byte getFreezeTime();
void removeTemporaryDisarmAlarm();
void setAutoArmForGroundAlarmEnabledTo(byte state);
private:
MemoryVariables memoryVariables;
Notification *notification;
Action *alarmSetting;
OpenWindowDetector *openWindowDetector;
byte isAutoArmForGroundAlarmEnabled = ENABLED;
};
#endif
lonas:
Is there any linux version for that what You mentioned ?
There certainly is, although I do not have a Linux installation of the Arduino IDE to tell you where they put the file. Search the directory where you have the Arduino IDE installed for "avr-objdump.exe."
I'm also not sure what temporary directory the Arduino IDE would use for building in Linux, but you should be able to tell when you build the code. Go to File->Preferences and then click the checkbox to "Show verbose output during: compilation." The next time you build, you'll see all of the commands run as your project builds. In those commands, you should be able to see a weird temporary directory that Arduino created when it built your project.
If you're getting to the point where you're wondering which of your code is consuming which resources, learning how to make a map file will be a very powerful tool.
As for comparing two map files, WinMerge is a Windows only program. There must be many similar programs for Linux, however. They list some here -> 14.04 - Best alternative for WinMerge - Ask Ubuntu
lonas
March 16, 2016, 11:19pm
13
All right - I have tracked it down to some particular example:
Including in main sketch button library which takes me 10% of memory - without object initialization..
#include <Button.h>
which looks like:
#ifndef Button_h
#define Button_h
#include <Arduino.h>
//#include <CommonConfiguration.h>
class Button
{
public:
Button(byte arduinoId, byte pin, byte shortPressActionId, byte buttonActionTypeId = 1, byte buttonTypeId = 1, byte holdPressActionId = 1, byte doublePressActionId = 1, byte relatedButtonActionId = 1);
void init();
byte getArduinoId();
unsigned int getActionId();
byte getRelatedActionId();
byte getButtonTypeId();
byte getButtonActionTypeId();
unsigned int getPressedActionId();
private:
byte arduinoId;
byte pin;
byte buttonTypeId;
byte buttonActionTypeId;
byte shortPressActionId;
byte holdPressActionId;
byte doublePressActionId;
byte relatedButtonActionId;
bool buttonState;
bool buttonPreviousState;
bool shouldWaitForDoublePress;
bool registerDoublePress;
bool singleOK; // whether it's OK to do a single click
long pressTime;
long releaseTime;
bool shouldIgnoreButtonReleaseBecauseOfHold;
bool waitForUp; // when held, whether to wait for the up event
bool holdEventPast; // whether or not the hold event happened already
byte readEvent();
bool isPress();
void setPressAttributes();
bool isRelease();
bool isDoublePress();
void setDoublePressAttributes();
bool wasPress(int event);
bool wasHold();
void setHoldAttributes();
bool wasLongHold();
bool hasSecondCommand();
};
#endif
RE READ POST #6 Your basic understanding of what is going on is complete CRAP
Mark
lonas
March 16, 2016, 11:36pm
15
Instance
holmes4:
Only ram for that instance of the object is allocated when the instance is created. The class may require other data space.
Mark
that is not creating instance of object
#include <Button.h>
that does
Button(ARDUINO_2, A8, BATH_ROOM_GROUND, LOCAL_ACTION, BUTTON, BATH_ROOM_GROUND_SHOWER),
so I dont get what You mean...
lonas
March 16, 2016, 11:49pm
16
All right I have found root cause of that behavior but if some one could explain me why its happening.
I have couple of entity classes under one library directory, like button, relay, move sensor (7 classes)
When I have moved button class to separate package/folder then include of button takes 0% of usage when moved back to entity package it takes 10%
why.. ?
The linker is a femme fatale in GCC's clothing.
Want a better answer? Post source code with instructions that demonstrates the problem.
lonas
March 18, 2016, 4:35pm
18
All right so lets do really simple experiment:
#ifndef Logger_h
#define Logger_h
#include <Arduino.h>
//#include <MemoryVariables.h>
//#include <MQTTClient.h>
class Logger
{
public:
//void initWith(MQTTClient *mqttClient);
void debugF(const __FlashStringHelper* log);
void debugS(String log);
void debugC(char* log);
private:
// MQTTClient *mqttClient;
//MemoryVariables memoryVariables;
bool isDebugEnable();
};
#endif
cpp
#include "Logger.h"
//void Logger::initWith(MQTTClient *mqttClient)
//{
//this->mqttClient = mqttClient;
//}
void Logger::debugF(const __FlashStringHelper* log)
{
if (isDebugEnable())
{
char arduinoName[20];
//strcpy_P(arduinoName, (char*)pgm_read_word(&(ARDUINO_NAMES[memoryVariables.getArduinoId()])));
Serial.print(arduinoName);
Serial.print(" ");
Serial.println(log);
}
}
void Logger::debugS(String log)
{
if (isDebugEnable())
{
char arduinoName[20];
//strcpy_P(arduinoName, (char*)pgm_read_word(&(ARDUINO_NAMES[memoryVariables.getArduinoId()])));
Serial.print(arduinoName);
Serial.print(" ");
Serial.println(log);
}
}
void Logger::debugC(char* log)
{
if (isDebugEnable())
{
Serial.print("- ");
Serial.println(log);
}
}
bool Logger::isDebugEnable()
{
return true;
//return memoryVariables.isDebugEnable();
}
import that library in new sketch
#include <Logger.h>
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
and now when I will return in isDebugEnable true complier shows 2% of dynamic memory used (182bytes)
when it set to false its 0 ....
who can explain me why??
system
March 18, 2016, 5:24pm
19
Well, Serial is going to take two lots of 64 bytes for the input and output buffers, plus the strings. . . .
Expanding on @AWOL 's answer...
Serial uses interrupts. By using interrupts, the linker is forced to bring part of Serial into the image even though Serial is not actually used by your sketch.
When isDebugEnable returns false the compiler (optimizer) determines that all your code referencing Serial is unreachable (dead) so the compiler eliminates that part of your code.