mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #10953 from gschorcht/sys/shell/heap_cmd/pr
sys/shell: add heap command
This commit is contained in:
commit
4b7c5915ec
@ -116,6 +116,28 @@ void cpu_init(void)
|
||||
periph_init();
|
||||
}
|
||||
|
||||
struct __freelist {
|
||||
size_t size;
|
||||
struct __freelist *next;
|
||||
};
|
||||
|
||||
extern struct __freelist *__flp;
|
||||
extern char *__malloc_heap_start;
|
||||
extern char *__malloc_heap_end;
|
||||
extern char *__brkval;
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
int heap_size = __malloc_heap_end - __malloc_heap_start;
|
||||
int free = __malloc_heap_end - __brkval;
|
||||
struct __freelist *fp;
|
||||
for (fp = __flp; fp; fp = fp->next) {
|
||||
free += fp->size;
|
||||
}
|
||||
printf("heap: %d (used %d, free %d) [bytes]\n",
|
||||
heap_size, heap_size - free, free);
|
||||
}
|
||||
|
||||
/* This is a vector which is aliased to __vector_default,
|
||||
* the vector executed when an ISR fires with no accompanying
|
||||
* ISR handler. This may be used along with the ISR() macro to
|
||||
|
@ -56,6 +56,11 @@ extern "C" {
|
||||
*/
|
||||
#define PUF_SRAM_ATTRIBUTES __attribute__((used, section(".noinit")))
|
||||
|
||||
/**
|
||||
* @brief Declare the heap_stats function as available
|
||||
*/
|
||||
#define HAVE_HEAP_STATS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -31,6 +31,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Declare the heap_stats function as available
|
||||
*/
|
||||
#define HAVE_HEAP_STATS
|
||||
|
||||
/**
|
||||
* @name Stack size configuration
|
||||
* @{
|
||||
|
@ -60,6 +60,9 @@
|
||||
|
||||
#ifdef MODULE_ESP_IDF_HEAP
|
||||
#include "heap/esp_heap_caps.h"
|
||||
#include "heap/include/multi_heap.h"
|
||||
#else
|
||||
#include "malloc.h"
|
||||
#endif
|
||||
|
||||
#define MHZ 1000000UL
|
||||
@ -218,6 +221,24 @@ void* IRAM_ATTR __wrap__calloc_r(struct _reent *r, size_t count, size_t size)
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int IRAM get_free_heap_size (void)
|
||||
{
|
||||
return heap_caps_get_free_size( MALLOC_CAP_DEFAULT );
|
||||
}
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
multi_heap_info_t hinfo;
|
||||
|
||||
heap_caps_get_info(&hinfo, MALLOC_CAP_DEFAULT);
|
||||
|
||||
size_t _free = hinfo.total_free_bytes;
|
||||
size_t _alloc = hinfo.total_allocated_bytes;
|
||||
|
||||
printf("heap: %u (used %u free %u) [bytes]\n",
|
||||
(unsigned)(_free + _alloc), (unsigned)_alloc, (unsigned)_free);
|
||||
}
|
||||
|
||||
#else /* MODULE_ESP_IDF_HEAP */
|
||||
|
||||
/* for compatibiliy with ESP-IDF heap functions */
|
||||
@ -242,21 +263,23 @@ extern uint8_t _eheap; /* end of heap (defined in esp32.common.ld) */
|
||||
extern uint8_t _sheap; /* start of heap (defined in esp32.common.ld) */
|
||||
extern uint8_t *heap_top; /* current top of heap as defined in newlib_syscalls_default */
|
||||
|
||||
#endif /* MODULE_ESP_IDF_HEAP */
|
||||
|
||||
unsigned int IRAM get_free_heap_size (void)
|
||||
{
|
||||
#if MODULE_ESP_IDF_HEAP
|
||||
return heap_caps_get_free_size( MALLOC_CAP_DEFAULT );
|
||||
#else
|
||||
return &_eheap - ((heap_top) ? heap_top : &_sheap);
|
||||
#endif
|
||||
struct mallinfo minfo = mallinfo();
|
||||
return &_eheap - &_sheap - minfo.uordblks;
|
||||
}
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
printf("heap: %u (used %u free %u)\n", (unsigned)(&_eheap - &_sheap),
|
||||
&_eheap - &_sheap - get_free_heap_size(), get_free_heap_size());
|
||||
}
|
||||
|
||||
#endif /* MODULE_ESP_IDF_HEAP */
|
||||
|
||||
/* alias for compatibility with espressif/wifi_libs */
|
||||
uint32_t esp_get_free_heap_size( void ) __attribute__((alias("get_free_heap_size")));
|
||||
|
||||
|
||||
/**
|
||||
* @name Other system functions
|
||||
*/
|
||||
|
@ -10,7 +10,6 @@ ifneq (, $(filter esp_sdk, $(USEMODULE)))
|
||||
LINKFLAGS += -Wl,-wrap=_malloc_r
|
||||
LINKFLAGS += -Wl,-wrap=_free_r
|
||||
LINKFLAGS += -Wl,-wrap=_realloc_r
|
||||
LINKFLAGS += -Wl,-wrap=mallinfo
|
||||
endif
|
||||
|
||||
ifneq (, $(filter esp_spiffs, $(USEMODULE)))
|
||||
|
@ -74,7 +74,9 @@ void *__real_realloc(void *ptr, size_t size);
|
||||
void *__real__malloc_r (struct _reent *r, size_t size);
|
||||
void __real__free_r (struct _reent *r, void *ptr);
|
||||
void *__real__realloc_r (struct _reent *r, void *ptr, size_t size);
|
||||
struct mallinfo __real_mallinfo(void);
|
||||
|
||||
extern uint8_t _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */
|
||||
extern uint8_t _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */
|
||||
|
||||
void* IRAM __wrap_malloc(size_t size)
|
||||
{
|
||||
@ -136,27 +138,6 @@ unsigned int get_free_heap_size (void)
|
||||
return xPortGetFreeHeapSize();
|
||||
}
|
||||
|
||||
extern uint8_t _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */
|
||||
extern uint8_t _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */
|
||||
|
||||
struct mallinfo __wrap_mallinfo(void)
|
||||
{
|
||||
struct mallinfo mi;
|
||||
|
||||
mi.arena = &_eheap - &_sheap;
|
||||
mi.fordblks = get_free_heap_size();
|
||||
mi.uordblks = mi.arena - mi.fordblks;
|
||||
mi.keepcost = mi.fordblks;
|
||||
return mi;
|
||||
}
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
struct mallinfo minfo = __wrap_mallinfo();
|
||||
ets_printf("heap: %d (used %d, free %d)\n",
|
||||
minfo.arena, minfo.uordblks, minfo.fordblks);
|
||||
}
|
||||
|
||||
void IRAM syscalls_init (void)
|
||||
{
|
||||
}
|
||||
@ -346,20 +327,20 @@ extern char _eheap; /* end of heap (defined in esp8266.riot-os.app.ld) */
|
||||
extern char _sheap; /* start of heap (defined in esp8266.riot-os.app.ld) */
|
||||
|
||||
unsigned int IRAM get_free_heap_size (void)
|
||||
{
|
||||
return (_cheap) ? &_eheap - _cheap : 0;
|
||||
}
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
struct mallinfo minfo = mallinfo();
|
||||
ets_printf("heap: %u (free %u), ", &_eheap - &_sheap, get_free_heap_size());
|
||||
ets_printf("sysmem: %d (used %d, free %d)\n",
|
||||
minfo.arena, minfo.uordblks, minfo.fordblks);
|
||||
return &_eheap - &_sheap - minfo.uordblks;
|
||||
}
|
||||
|
||||
#endif /* MODULE_ESP_SDK */
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
ets_printf("heap: %u (used %d, free %u) [bytes]\n",
|
||||
&_eheap - &_sheap, &_eheap - &_sheap - get_free_heap_size(),
|
||||
get_free_heap_size());
|
||||
}
|
||||
|
||||
int _rename_r (struct _reent *r, const char* old, const char* new)
|
||||
{
|
||||
DEBUG("%s: system function does not exist\n", __func__);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "thread.h"
|
||||
#include "irq.h"
|
||||
@ -378,3 +379,17 @@ void thread_yield_higher(void)
|
||||
/* Latency of SW intr can be 4-7 cycles; wait for the SW intr */
|
||||
__asm__ volatile ("wfi");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print heap statistics
|
||||
*/
|
||||
void heap_stats(void)
|
||||
{
|
||||
extern char _heap_start; /* defined in linker script */
|
||||
extern char _heap_end; /* defined in linker script */
|
||||
|
||||
long int heap_size = &_heap_end - &_heap_start;
|
||||
struct mallinfo minfo = mallinfo();
|
||||
printf("heap: %ld (used %u, free %ld) [bytes]\n",
|
||||
heap_size, minfo.uordblks, heap_size - minfo.uordblks);
|
||||
}
|
||||
|
@ -34,6 +34,11 @@
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Declare the heap_stats function as available
|
||||
*/
|
||||
#define HAVE_HEAP_STATS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@ ifeq ($(USE_UHI_SYSCALLS),1)
|
||||
#Use UHI to handle syscalls
|
||||
export LINKFLAGS += -luhi
|
||||
export USEMODULE += newlib_syscalls_mips_uhi
|
||||
CFLAGS += -DHAVE_HEAP_STATS
|
||||
else
|
||||
#Use RIOT to handle syscalls (default)
|
||||
export USEMODULE += newlib_syscalls_default
|
||||
|
@ -7,11 +7,13 @@
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
#include <mips/hal.h>
|
||||
#include <mips/m32c0.h>
|
||||
#include <mips/regdef.h>
|
||||
#include <mips/asm.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "periph/uart.h"
|
||||
#include "periph/timer.h"
|
||||
@ -83,3 +85,35 @@ void cpu_init(void)
|
||||
/* trigger static peripheral initialization */
|
||||
periph_init();
|
||||
}
|
||||
|
||||
#ifdef MODULE_NEWLIB_SYSCALLS_DEFAULT
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
puts("heap statistics are not supported for newlib_syscalls_default");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern char _end[]; /* defined in linker script */
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
void *ram_base;
|
||||
void *ram_extent;
|
||||
unsigned long heap_size;
|
||||
|
||||
_get_ram_range (&ram_base, &ram_extent);
|
||||
/* If the _end symbol is within the RAM then use _end. */
|
||||
if ((void*)_end > ram_base && (void*)_end < ram_extent) {
|
||||
heap_size = ram_extent - (void*)_end;
|
||||
}
|
||||
else {
|
||||
heap_size = ram_extent - ram_base;
|
||||
}
|
||||
struct mallinfo minfo = mallinfo();
|
||||
printf("heap: %lu (used %lu, free %lu) [bytes]\n",
|
||||
heap_size, minfo.uordblks, heap_size - minfo.uordblks);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -77,6 +77,11 @@ extern "C" {
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Declare the heap_stats function as available
|
||||
*/
|
||||
#define HAVE_HEAP_STATS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -224,6 +224,10 @@ free(void *p)
|
||||
|
||||
state = irq_disable();
|
||||
|
||||
if (__brkval == NULL) {
|
||||
__brkval = __malloc_heap_start;
|
||||
}
|
||||
|
||||
/* ISO C says free(NULL) must be a no-op */
|
||||
if (p == NULL) {
|
||||
irq_restore(state);
|
||||
@ -457,4 +461,26 @@ calloc(size_t nele, size_t size)
|
||||
return p;
|
||||
}
|
||||
|
||||
void heap_stats(void)
|
||||
{
|
||||
if (__brkval == NULL) {
|
||||
__brkval = __malloc_heap_start;
|
||||
}
|
||||
|
||||
long int heap_size = __malloc_heap_end - __malloc_heap_start;
|
||||
long int free = __malloc_heap_end - __brkval;
|
||||
struct __freelist *fp;
|
||||
for (fp = __flp; fp; fp = fp->nx) {
|
||||
free += fp->sz;
|
||||
}
|
||||
printf("heap: %ld (used %ld, free %ld) [bytes]\n",
|
||||
heap_size, heap_size - free, free);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void heap_stats(void) {
|
||||
puts("heap statistics are not supported");
|
||||
}
|
||||
|
||||
#endif /* MODULE_MSP430_MALLOC */
|
||||
|
@ -41,6 +41,7 @@ PSEUDOMODULES += gnrc_sixlowpan_router_default
|
||||
PSEUDOMODULES += gnrc_sock_check_reuse
|
||||
PSEUDOMODULES += gnrc_txtsnd
|
||||
PSEUDOMODULES += i2c_scan
|
||||
PSEUDOMODULES += heap_cmd
|
||||
PSEUDOMODULES += l2filter_blacklist
|
||||
PSEUDOMODULES += l2filter_whitelist
|
||||
PSEUDOMODULES += lis2dh12_i2c
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <unistd.h>
|
||||
#include <reent.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -122,6 +123,24 @@ void *_sbrk_r(struct _reent *r, ptrdiff_t incr)
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print heap statistics
|
||||
*
|
||||
* If the CPU does not provide its own heap handling and heap_stats function,
|
||||
* but instead uses the newlib_syscall_default function, this function outputs
|
||||
* the heap statistics. If the CPU provides its own heap_stats function, it
|
||||
* should define HAVE_HEAP_STATS in its cpu_conf.h file.
|
||||
*/
|
||||
#ifndef HAVE_HEAP_STATS
|
||||
__attribute__((weak)) void heap_stats(void)
|
||||
{
|
||||
struct mallinfo minfo = mallinfo();
|
||||
long int heap_size = &_eheap - &_sheap;
|
||||
printf("heap: %ld (used %d, free %ld) [bytes]\n",
|
||||
heap_size, minfo.uordblks, heap_size - minfo.uordblks);
|
||||
}
|
||||
#endif /* HAVE_HEAP_STATS */
|
||||
|
||||
#endif /*__mips__*/
|
||||
|
||||
/**
|
||||
|
@ -11,6 +11,9 @@ endif
|
||||
ifneq (,$(filter ps,$(USEMODULE)))
|
||||
SRC += sc_ps.c
|
||||
endif
|
||||
ifneq (,$(filter heap_cmd,$(USEMODULE)))
|
||||
SRC += sc_heap.c
|
||||
endif
|
||||
ifneq (,$(filter sht1x,$(USEMODULE)))
|
||||
SRC += sc_sht1x.c
|
||||
endif
|
||||
|
@ -18,14 +18,24 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu_conf.h"
|
||||
|
||||
#if defined(MODULE_NEWLIB_SYSCALLS_DEFAULT) || defined (HAVE_HEAP_STATS)
|
||||
extern void heap_stats(void);
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
int _heap_handler(int argc, char **argv)
|
||||
{
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
#if defined(MODULE_NEWLIB_SYSCALLS_DEFAULT) || defined (HAVE_HEAP_STATS)
|
||||
heap_stats();
|
||||
|
||||
return 0;
|
||||
#else
|
||||
printf("heap statistics are not supported for %s cpu\n", RIOT_CPU);
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ extern int _reboot_handler(int argc, char **argv);
|
||||
extern int _id_handler(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_LPC_COMMON
|
||||
#ifdef MODULE_HEAP_CMD
|
||||
extern int _heap_handler(int argc, char **argv);
|
||||
#endif
|
||||
|
||||
@ -168,8 +168,8 @@ const shell_command_t _shell_command_list[] = {
|
||||
#ifdef MODULE_CONFIG
|
||||
{"id", "Gets or sets the node's id.", _id_handler},
|
||||
#endif
|
||||
#ifdef MODULE_LPC_COMMON
|
||||
{"heap", "Shows the heap state for the LPC2387 on the command shell.", _heap_handler},
|
||||
#ifdef MODULE_HEAP_CMD
|
||||
{"heap", "Prints heap statistics.", _heap_handler},
|
||||
#endif
|
||||
#ifdef MODULE_PS
|
||||
{"ps", "Prints information about running threads.", _ps_handler},
|
||||
|
10
tests/heap_cmd/Makefile
Normal file
10
tests/heap_cmd/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-uno arduino-nano
|
||||
|
||||
USEMODULE += heap_cmd
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
5
tests/heap_cmd/README.md
Normal file
5
tests/heap_cmd/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# heap_cmd application
|
||||
|
||||
Shell-based test application for the heap functions `malloc`, `free`
|
||||
and `heap_stats`. Use the `help` command to get more information on how to use
|
||||
it.
|
70
tests/heap_cmd/main.c
Normal file
70
tests/heap_cmd/main.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Gunar Schorcht <gunar@schorcht.net>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Shell-based test application for heap functions
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "shell_commands.h"
|
||||
#include "shell.h"
|
||||
|
||||
static int malloc_cmd(int argc, char **argv)
|
||||
{
|
||||
static void *ptr = 0;
|
||||
if (argc < 2) {
|
||||
printf("usage: %s <bytes>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
size_t size = atoi(argv[1]);
|
||||
ptr = malloc(size);
|
||||
printf("allocated %p\n", ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int free_cmd(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
printf("usage: %s <ptr in hex> returned from malloc, e.g., 0x1234\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int p = strtoul(argv[1], NULL, 16);
|
||||
void *ptr = (void *)p;
|
||||
free(ptr);
|
||||
printf("freed %p\n", ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const shell_command_t shell_commands[] = {
|
||||
{ "malloc", "malloc <size>", malloc_cmd },
|
||||
{ "free", "free <addr in hex> returned from malloc, e.g., 0x1234", free_cmd },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
puts("Shell-based test application for heap functions.\n"
|
||||
"Use the 'help' command to get more information on how to use it.");
|
||||
|
||||
/* define buffer to be used by the shell */
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
|
||||
/* define own shell commands */
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
35
tests/heap_cmd/tests/01-run.py
Executable file
35
tests/heap_cmd/tests/01-run.py
Executable file
@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2019 Gunar Schorcht <gunar@schorcht.net>
|
||||
#
|
||||
# This file is subject to the terms and conditions of the GNU Lesser
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
# directory for more details.
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
# check startup message
|
||||
child.expect('Shell-based test application for heap functions.')
|
||||
child.sendline('heap')
|
||||
ret = child.expect(['heap: \d+ \(used \d+, free \d+\) \[bytes\]', 'heap statistics are not supported'])
|
||||
if ret == 1:
|
||||
return
|
||||
child.sendline('malloc 100')
|
||||
child.expect('allocated 0x')
|
||||
addr = child.readline()
|
||||
addr = addr[:-2]
|
||||
child.expect_exact('> ')
|
||||
child.sendline('heap')
|
||||
child.expect('heap: \d+ \(used \d+, free \d+\) \[bytes\]')
|
||||
child.sendline('free 0x' + addr)
|
||||
child.expect('freed 0x' + addr)
|
||||
child.expect_exact('>')
|
||||
child.sendline('heap')
|
||||
child.expect('heap: \d+ \(used \d+, free \d+\) \[bytes\]')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
Loading…
Reference in New Issue
Block a user