1
0
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:
Kevin "Tristate Tom" Weiss 2019-10-04 13:49:57 +02:00 committed by GitHub
commit 4b7c5915ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 317 additions and 43 deletions

View File

@ -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

View File

@ -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

View File

@ -31,6 +31,11 @@
extern "C" {
#endif
/**
* @brief Declare the heap_stats function as available
*/
#define HAVE_HEAP_STATS
/**
* @name Stack size configuration
* @{

View File

@ -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
*/

View File

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

View File

@ -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__);

View File

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

View File

@ -34,6 +34,11 @@
#endif
/** @} */
/**
* @brief Declare the heap_stats function as available
*/
#define HAVE_HEAP_STATS
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -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

View File

@ -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

View File

@ -77,6 +77,11 @@ extern "C" {
#endif
/** @} */
/**
* @brief Declare the heap_stats function as available
*/
#define HAVE_HEAP_STATS
#ifdef __cplusplus
}
#endif

View File

@ -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 */

View File

@ -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

View File

@ -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__*/
/**

View File

@ -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

View File

@ -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
}

View File

@ -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
View 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
View 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
View 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
View 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))