forked from StopPointTeam/TaiChi
新增修改后的 MemoryUsage 库
This commit is contained in:
parent
67ff9526cc
commit
d38c4ead27
115
TaiChi/MemoryUsage.cpp
Normal file
115
TaiChi/MemoryUsage.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
MemoryUsage.c - MemoryUsage library
|
||||
Copyright (c) 2015 Thierry Paris. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*! \file MemoryUsage.cpp
|
||||
|
||||
Main library code file.
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "MemoryUsage.h"
|
||||
|
||||
/// Thanks to adafruit : https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
|
||||
int mu_freeRam()
|
||||
{
|
||||
//extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
|
||||
}
|
||||
|
||||
/// Copy / adaptation of the library StackPaint available here : https://github.com/WickedDevice/StackPaint
|
||||
|
||||
#define STACK_CANARY 0xc5
|
||||
|
||||
void mu_StackPaint(void) __attribute__((naked)) __attribute__((section(".init1")));
|
||||
|
||||
|
||||
/// Function called before any other function.
|
||||
void mu_StackPaint(void)
|
||||
{
|
||||
#if 1
|
||||
uint8_t *p = &_end;
|
||||
|
||||
while (p <= &__stack)
|
||||
{
|
||||
*p = STACK_CANARY;
|
||||
p++;
|
||||
}
|
||||
#else
|
||||
__asm volatile (
|
||||
" ldi r30,lo8(_end)\n"
|
||||
" ldi r31,hi8(_end)\n"
|
||||
" ldi r24,lo8(0xc5)\n" // STACK_CANARY = 0xc5
|
||||
" ldi r25,hi8(__stack)\n"
|
||||
" rjmp .cmp\n"
|
||||
".loop:\n"
|
||||
" st Z+,r24\n"
|
||||
".cmp:\n"
|
||||
" cpi r30,lo8(__stack)\n"
|
||||
" cpc r31,r25\n"
|
||||
" brlo .loop\n"
|
||||
" breq .loop"::);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Checks the first undecorated byte.
|
||||
uint16_t mu_StackCount(void)
|
||||
{
|
||||
uint8_t *p = (__brkval == 0 ? (uint8_t *) &__heap_start : __brkval);
|
||||
|
||||
while (*p == STACK_CANARY && (int) p <= SP)
|
||||
p++;
|
||||
|
||||
return (uint16_t)RAMEND - (uint16_t)p;
|
||||
}
|
||||
|
||||
/// Modified function from http://www.avr-developers.com/mm/memoryusage.html
|
||||
void SRamDisplay(void)
|
||||
{
|
||||
int data_size = (int)&__data_end - (int)&__data_start;
|
||||
int bss_size = (int)&__bss_end - (int)&__data_end;
|
||||
int heap_end = (int) (__brkval == 0 ? (uint8_t *) &__heap_start : __brkval);
|
||||
//int heap_end = (int)SP - (int)&__malloc_margin;
|
||||
int heap_size = heap_end - (int)&__bss_end;
|
||||
int stack_size = RAMEND - (int)SP + 1;
|
||||
int available = (RAMEND - (int)&__data_start + 1);
|
||||
|
||||
available -= data_size + bss_size + heap_size + stack_size;
|
||||
|
||||
NeoSerial.print(F("+----------------+ ")); NeoSerial.print((int)&__data_start); NeoSerial.println(" (__data_start)");
|
||||
NeoSerial.print(F("+ data +")); NeoSerial.println();
|
||||
NeoSerial.print(F("+ variables + size = ")); NeoSerial.println(data_size);
|
||||
NeoSerial.print(F("+----------------+ ")); NeoSerial.print((int)&__data_end); NeoSerial.println(" (__data_end / __bss_start)");
|
||||
NeoSerial.print(F("+ bss +")); NeoSerial.println();
|
||||
NeoSerial.print(F("+ variables + size = ")); NeoSerial.println(bss_size);
|
||||
NeoSerial.print(F("+----------------+ ")); NeoSerial.print((int)&__bss_end); NeoSerial.println(" (__bss_end / __heap_start)");
|
||||
NeoSerial.print(F("+ heap + size = ")); NeoSerial.println(heap_size);
|
||||
NeoSerial.print(F("+----------------+ ")); NeoSerial.print((int)heap_end); NeoSerial.println(" (__brkval if not 0, or __heap_start)");
|
||||
NeoSerial.print(F("+ +")); NeoSerial.println();
|
||||
NeoSerial.print(F("+ +")); NeoSerial.println();
|
||||
NeoSerial.print(F("+ FREE RAM + size = ")); NeoSerial.println(available);
|
||||
NeoSerial.print(F("+ +")); NeoSerial.println();
|
||||
NeoSerial.print(F("+ +")); NeoSerial.println();
|
||||
NeoSerial.print(F("+----------------+ ")); NeoSerial.print((int)SP); NeoSerial.println(" (SP)");
|
||||
NeoSerial.print(F("+ stack + size = ")); NeoSerial.println(stack_size);
|
||||
NeoSerial.print(F("+----------------+ ")); NeoSerial.print((int)RAMEND); NeoSerial.println(" (RAMEND / __stack)");
|
||||
|
||||
NeoSerial.println();
|
||||
NeoSerial.println();
|
||||
}
|
||||
188
TaiChi/MemoryUsage.h
Normal file
188
TaiChi/MemoryUsage.h
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
MemoryUsage.h - MemoryUsage library V2.10
|
||||
Copyright (c) 2015 Thierry Paris. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __MemoryUsage_h__
|
||||
#define __MemoryUsage_h__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <NeoHWSerial.h>
|
||||
|
||||
/*! \mainpage
|
||||
|
||||
A full explanation in french can be read at http://www.locoduino.org/ecrire/?exec=article&action=redirect&type=article&id=149 .
|
||||
|
||||
Roughly, the SRAM memory is divided into four areas: the static data, the heap, the free ram and the stack.
|
||||
|
||||
The static data size is given by the compiler itself after the building. this is filled by all variables and
|
||||
arrays declared in global scope, or with 'static' keyword.
|
||||
|
||||
The heap is filled with all the dynamic allocations done with 'new' keyword or 'malloc' functions.
|
||||
|
||||
The stack start from the end of the SRAM area and grow and shrink downward at each function call, it stores
|
||||
all the local data internal to a function, function arguments (depending of the architecture, arguments can be
|
||||
stored in CPU registers to improve speed...) , and addresses for function returns to caller.
|
||||
|
||||
SRAM memory
|
||||
\verbatim
|
||||
+---------------+------------------+---------------------------------------------+-----------------+
|
||||
| | | | |
|
||||
| | | | |
|
||||
| static | | | |
|
||||
| data | heap | free ram | stack |
|
||||
| | | | |
|
||||
| | | | |
|
||||
| | | | |
|
||||
+---------------+------------------+---------------------------------------------+-----------------+
|
||||
_end or __heap_start __brkval SP RAMEND
|
||||
\endverbatim
|
||||
|
||||
Source : http://www.nongnu.org/avr-libc/user-manual/malloc.html
|
||||
|
||||
MemoryUsage try to help you to find the actual memory status with differents strategies, but dont forget
|
||||
that when you observe something, you change the result of the observation : execution time is consumed
|
||||
by the analysis tools, and memory used will grow because of these tools !
|
||||
|
||||
1. First, there are the MACROs to show memory areas start/end addresses and actual sizes.
|
||||
|
||||
2. Second, there is a display function to show a 'map' of the memory...
|
||||
|
||||
3. Third, a function can give you the current size of the free ram using a stack tag, which is more accurate
|
||||
than the MACRO.
|
||||
|
||||
4. Fourth, an elegant way to try to understand how much size has reached the stack during execution.
|
||||
It will 'decorate' the internal memory, and try to identify after a moment of execution at what place
|
||||
the first byte of the memory is not anymore decorated...
|
||||
The function mu_StackPaint will be called _before the setup() function of your sketch, to 'paint' or
|
||||
'decorate' all the bytes of the SRAM momery with a particular code, called the CANARY... Later, a function
|
||||
mu_StackCount can be called to get the actual maximum size reached by the stack by counter the byte
|
||||
no more painted.
|
||||
This is a copy / adaptation of the library StackPaint available here : https://github.com/WickedDevice/StackPaint
|
||||
|
||||
5. And five at least, and because a stack grow and shrink continuously, the macros STACK_DECLARE / STACK_COMPUTE / STACK_PRINT
|
||||
try to get the greatest size of the stack by 'sampling' the execution.
|
||||
Start your code by
|
||||
|
||||
#include <MemoryUsage.h>
|
||||
|
||||
STACK_DECLARE
|
||||
|
||||
void setup()
|
||||
...
|
||||
|
||||
then add a STACK_COMPUTE in any function that can be called :
|
||||
|
||||
void subFonction()
|
||||
{
|
||||
double v[SIZE];
|
||||
STACK_COMPUTE;
|
||||
|
||||
.... // do things
|
||||
}
|
||||
|
||||
and finish by printing on the console the biggest size of the stack with STACK_PRINT or STACK_PRINT_TEXT.
|
||||
Be careful with this method, this introduce some code in every function of your sketch, so if the timing
|
||||
is important for your applicaion, take care of it !
|
||||
*/
|
||||
|
||||
/*! \file MemoryUsage.h
|
||||
|
||||
Main library header file.
|
||||
*/
|
||||
|
||||
extern uint8_t _end;
|
||||
extern uint8_t __stack;
|
||||
extern uint8_t *__brkval;
|
||||
extern uint8_t *__data_start;
|
||||
extern uint8_t *__data_end;
|
||||
extern uint8_t *__heap_start;
|
||||
extern uint8_t *__heap_end;
|
||||
extern uint8_t *__bss_start;
|
||||
extern uint8_t *__bss_end;
|
||||
|
||||
//
|
||||
// Memory addresses
|
||||
//
|
||||
|
||||
/// Print data start on NeoSerial console.
|
||||
#define MEMORY_PRINT_START { NeoSerial.print(F("Data start:")); NeoSerial.println((int) &__data_start); }
|
||||
/// Print data end / heap start on NeoSerial console.
|
||||
#define MEMORY_PRINT_HEAPSTART { NeoSerial.print(F("Heap start:")); NeoSerial.println((int)&__heap_start); }
|
||||
/// Print heap end / free ram area on NeoSerial console.
|
||||
#define MEMORY_PRINT_HEAPEND { NeoSerial.print(F("Heap end:")); NeoSerial.println(__brkval == 0 ? (int)&__heap_start : (int)__brkval); }
|
||||
/// Print free ram end / stack start on NeoSerial console.
|
||||
#define MEMORY_PRINT_STACKSTART { NeoSerial.print(F("Stack start:")); NeoSerial.println((int) SP); }
|
||||
/// Print end of memory on NeoSerial console.
|
||||
#define MEMORY_PRINT_END { NeoSerial.print(F("Stack end:")); NeoSerial.println((int) RAMEND); }
|
||||
|
||||
/// Print heap size on NeoSerial console.
|
||||
#define MEMORY_PRINT_HEAPSIZE { NeoSerial.print(F("Heap size:")); NeoSerial.println((int) (__brkval == 0 ? (int)&__heap_start : (int)__brkval) - (int)&__heap_start); }
|
||||
/// Print stack size on NeoSerial console.
|
||||
#define MEMORY_PRINT_STACKSIZE { NeoSerial.print(F("Stack size:")); NeoSerial.println((int) RAMEND - (int)SP); }
|
||||
/// Print free ram size on NeoSerial console.
|
||||
#define MEMORY_PRINT_FREERAM { NeoSerial.print(F("Free ram:")); NeoSerial.println((int) SP - (int) (__brkval == 0 ? (int)&__heap_start : (int)__brkval)); }
|
||||
/// Print total SRAM size on NeoSerial console.
|
||||
#define MEMORY_PRINT_TOTALSIZE { NeoSerial.print(F("SRAM size:")); NeoSerial.println((int) RAMEND - (int) &__data_start); }
|
||||
|
||||
/// Displays the 'map' of the current state of the Arduino's SRAM memory on the NeoSerial console.
|
||||
void SRamDisplay(void);
|
||||
|
||||
//
|
||||
// Stack count part. STACK_COMPUTE will get the maximum size of the stack at the moment...
|
||||
//
|
||||
|
||||
/// Must be used only one time, outside any function.
|
||||
#define STACK_DECLARE unsigned int mu_stack_size = (RAMEND - SP);
|
||||
|
||||
/// Must be called to update the current maximum size of the stack, at each function beginning.
|
||||
#define STACK_COMPUTE { mu_stack_size = (RAMEND - SP) > mu_stack_size ? (RAMEND - SP) : mu_stack_size;}
|
||||
|
||||
/// Compute the current maximum and show it now with customized text.
|
||||
#define STACK_PRINT_TEXT(text) { STACK_COMPUTE; NeoSerial.print(text); NeoSerial.println(mu_stack_size); }
|
||||
|
||||
/// Compute the current maximum and show it now with default text.
|
||||
#define STACK_PRINT STACK_PRINT_TEXT(F("Stack Maximum Size (Instrumentation method): "));
|
||||
|
||||
//
|
||||
// Free Ram part.
|
||||
//
|
||||
|
||||
/// Shows the current free SRAM memory with customized text.
|
||||
#define FREERAM_PRINT_TEXT(text) NeoSerial.print(text); NeoSerial.println(mu_freeRam());
|
||||
|
||||
/// Shows the current free SRAM memory with default text.
|
||||
#define FREERAM_PRINT FREERAM_PRINT_TEXT(F("Free Ram Size: "));
|
||||
|
||||
/// Show the free Ram size on console.
|
||||
int mu_freeRam(void);
|
||||
|
||||
//
|
||||
// StackPaint part. This macro gives a view of used stack area at the end of execution...
|
||||
//
|
||||
|
||||
/// Show the stack size on console.
|
||||
uint16_t mu_StackCount(void);
|
||||
|
||||
/// Compute the current maximum and show it now with customized text.
|
||||
#define STACKPAINT_PRINT_TEXT(text) { NeoSerial.print(text); NeoSerial.println(mu_StackCount()); }
|
||||
|
||||
/// Compute the current maximum and show it now with default text.
|
||||
#define STACKPAINT_PRINT STACKPAINT_PRINT_TEXT(F("Stack Maximum Size (Painting method): "));
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user