From 17e44c73dfe56a939731606b3c2394d2b3148db2 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 19 Oct 2023 17:28:08 +0100 Subject: [PATCH] memory: Support debug tracking of memory usage New function coap_dump_memory_type_counts(). Requires COAP_MEMORY_TYPE_TRACK to be defined as 1. --- include/coap3/coap_mem.h | 12 ++++ libcoap-3.map | 1 + libcoap-3.sym | 1 + src/coap_mem.c | 151 +++++++++++++++++++++++++++++++++++++-- src/coap_net.c | 4 +- 5 files changed, 161 insertions(+), 8 deletions(-) diff --git a/include/coap3/coap_mem.h b/include/coap3/coap_mem.h index f875c36625..ad6a464ad9 100644 --- a/include/coap3/coap_mem.h +++ b/include/coap3/coap_mem.h @@ -64,6 +64,7 @@ typedef enum { COAP_OSCORE_EP, COAP_OSCORE_BUF, COAP_COSE, + COAP_MEM_TAG_LAST } coap_memory_tag_t; #ifndef WITH_LWIP @@ -106,6 +107,15 @@ void *coap_realloc_type(coap_memory_tag_t type, void *p, size_t size); */ void coap_free_type(coap_memory_tag_t type, void *p); +/** + * Dumps the current usage of malloc'd memory types. + * + * Requires COAP_MEMORY_TYPE_TRACK to be defined to 1. + * + * @param log_level The logging level to use. + */ +void coap_dump_memory_type_counts(coap_log_t log_level); + /** * Wrapper function to coap_malloc_type() for backwards compatibility. */ @@ -161,6 +171,8 @@ coap_free(void *pointer) { LWIP_ASSERT("coap_free must not be used in lwIP", 0); } +#define coap_dump_memory_type_counts(l) coap_lwip_dump_memory_pools(l) + #endif /* WITH_LWIP */ #endif /* COAP_MEM_H_ */ diff --git a/libcoap-3.map b/libcoap-3.map index 62fe5a3fbd..e0a634f42b 100644 --- a/libcoap-3.map +++ b/libcoap-3.map @@ -83,6 +83,7 @@ global: coap_dtls_psk_is_supported; coap_dtls_rpk_is_supported; coap_dtls_set_log_level; + coap_dump_memory_type_counts; coap_encode_var_safe8; coap_encode_var_safe; coap_endpoint_set_default_mtu; diff --git a/libcoap-3.sym b/libcoap-3.sym index 8ad20f72c6..8fbc21f425 100644 --- a/libcoap-3.sym +++ b/libcoap-3.sym @@ -81,6 +81,7 @@ coap_dtls_pki_is_supported coap_dtls_psk_is_supported coap_dtls_rpk_is_supported coap_dtls_set_log_level +coap_dump_memory_type_counts coap_encode_var_safe coap_encode_var_safe8 coap_endpoint_set_default_mtu diff --git a/src/coap_mem.c b/src/coap_mem.c index 776a4d5189..b134abe1f0 100644 --- a/src/coap_mem.c +++ b/src/coap_mem.c @@ -15,6 +15,14 @@ #include "coap3/coap_internal.h" +#ifndef WITH_LWIP +#if COAP_MEMORY_TYPE_TRACK +static int track_counts[COAP_MEM_TAG_LAST]; +static int peak_counts[COAP_MEM_TAG_LAST]; +static int fail_counts[COAP_MEM_TAG_LAST]; +#endif /* COAP_MEMORY_TYPE_TRACK */ +#endif /* ! WITH_LWIP */ + #if defined(RIOT_VERSION) && defined(MODULE_MEMARRAY) #include @@ -423,11 +431,26 @@ coap_malloc_type(coap_memory_tag_t type, size_t size) { if (!ptr) coap_log_warn("coap_malloc_type: Failure (no free blocks) for type %d\n", type); +#if COAP_MEMORY_TYPE_TRACK + assert(type < COAP_MEM_TAG_LAST); + if (ptr) { + track_counts[type]++; + if (track_counts[type] > peak_counts[type]) + peak_counts[type] = track_counts[type]; + } else { + fail_counts[type]++; + } +#endif /* COAP_MEMORY_TYPE_TRACK */ return ptr; } void coap_free_type(coap_memory_tag_t type, void *object) { +#if COAP_MEMORY_TYPE_TRACK + assert(type < COAP_MEM_TAG_LAST); + if (object) + track_counts[type]--; +#endif /* COAP_MEMORY_TYPE_TRACK */ if (object != NULL) memarray_free(get_container(type), object); } @@ -452,8 +475,9 @@ coap_realloc_type(coap_memory_tag_t type, void *p, size_t size) { return p; } return coap_malloc_type(type, size); + } -#else /* ! RIOT_VERSION */ +#else /* ! RIOT_VERSION && ! MODULE_MEMARRAY */ #if defined(HAVE_MALLOC) || defined(__MINGW32__) #include @@ -464,19 +488,51 @@ coap_memory_init(void) { void * coap_malloc_type(coap_memory_tag_t type, size_t size) { + void *ptr; + (void)type; - return malloc(size); + ptr = malloc(size); +#if COAP_MEMORY_TYPE_TRACK + assert(type < COAP_MEM_TAG_LAST); + if (ptr) { + track_counts[type]++; + if (track_counts[type] > peak_counts[type]) + peak_counts[type] = track_counts[type]; + } else { + fail_counts[type]++; + } +#endif /* COAP_MEMORY_TYPE_TRACK */ + return ptr; } void * coap_realloc_type(coap_memory_tag_t type, void *p, size_t size) { + void *ptr; + (void)type; - return realloc(p, size); + ptr = realloc(p, size); +#if COAP_MEMORY_TYPE_TRACK + if (ptr) { + assert(type < COAP_MEM_TAG_LAST); + if (!p) + track_counts[type]++; + if (track_counts[type] > peak_counts[type]) + peak_counts[type] = track_counts[type]; + } else { + fail_counts[type]++; + } +#endif /* COAP_MEMORY_TYPE_TRACK */ + return ptr; } void coap_free_type(coap_memory_tag_t type, void *p) { (void)type; +#if COAP_MEMORY_TYPE_TRACK + assert(type < COAP_MEM_TAG_LAST); + if (p) + track_counts[type]--; +#endif /* COAP_MEMORY_TYPE_TRACK */ free(p); } @@ -491,20 +547,105 @@ coap_memory_init(void) { void * coap_malloc_type(coap_memory_tag_t type, size_t size) { - return heapmem_alloc(size); + void *ptr = heapmem_alloc(size); + +#if COAP_MEMORY_TYPE_TRACK + assert(type < COAP_MEM_TAG_LAST); + if (ptr) { + track_counts[type]++; + if (track_counts[type] > peak_counts[type]) + peak_counts[type] = track_counts[type]; + } else { + fail_counts[type]++; + } +#endif /* COAP_MEMORY_TYPE_TRACK */ + return ptr; } void * coap_realloc_type(coap_memory_tag_t type, void *p, size_t size) { - return heapmem_realloc(p, size); + void *ptr = heapmem_realloc(p, size); +#if COAP_MEMORY_TYPE_TRACK + if (ptr) { + assert(type < COAP_MEM_TAG_LAST); + if (!p) + track_counts[type]++; + if (track_counts[type] > peak_counts[type]) + peak_counts[type] = track_counts[type]; + } else { + fail_counts[type]++; + } +#endif /* COAP_MEMORY_TYPE_TRACK */ + return ptr; } void coap_free_type(coap_memory_tag_t type, void *ptr) { +#if COAP_MEMORY_TYPE_TRACK + assert(type < COAP_MEM_TAG_LAST); + if (ptr) + track_counts[type]--; +#endif /* COAP_MEMORY_TYPE_TRACK */ heapmem_free(ptr); } + #endif /* WITH_CONTIKI */ #endif /* ! HAVE_MALLOC */ #endif /* ! RIOT_VERSION */ + +#ifndef WITH_LWIP +#define MAKE_CASE(n) case n: name = #n; break +void +coap_dump_memory_type_counts(coap_log_t level) { +#if COAP_MEMORY_TYPE_TRACK + int i; + + coap_log(level, "* Memory type counts\n"); + for (i = 0; i < COAP_MEM_TAG_LAST; i++) { + const char *name = "?"; + + + switch (i) { + MAKE_CASE(COAP_STRING); + MAKE_CASE(COAP_ATTRIBUTE_NAME); + MAKE_CASE(COAP_ATTRIBUTE_VALUE); + MAKE_CASE(COAP_PACKET); + MAKE_CASE(COAP_NODE); + MAKE_CASE(COAP_CONTEXT); + MAKE_CASE(COAP_ENDPOINT); + MAKE_CASE(COAP_PDU); + MAKE_CASE(COAP_PDU_BUF); + MAKE_CASE(COAP_RESOURCE); + MAKE_CASE(COAP_RESOURCEATTR); + MAKE_CASE(COAP_DTLS_SESSION); + MAKE_CASE(COAP_SESSION); + MAKE_CASE(COAP_OPTLIST); + MAKE_CASE(COAP_CACHE_KEY); + MAKE_CASE(COAP_CACHE_ENTRY); + MAKE_CASE(COAP_LG_XMIT); + MAKE_CASE(COAP_LG_CRCV); + MAKE_CASE(COAP_LG_SRCV); + MAKE_CASE(COAP_DIGEST_CTX); + MAKE_CASE(COAP_SUBSCRIPTION); + MAKE_CASE(COAP_DTLS_CONTEXT); + MAKE_CASE(COAP_OSCORE_COM); + MAKE_CASE(COAP_OSCORE_SEN); + MAKE_CASE(COAP_OSCORE_REC); + MAKE_CASE(COAP_OSCORE_EX); + MAKE_CASE(COAP_OSCORE_EP); + MAKE_CASE(COAP_OSCORE_BUF); + MAKE_CASE(COAP_COSE); + case COAP_MEM_TAG_LAST: + default: + break; + } + coap_log(level, "* %-20s in-use %3d peak %3d failed %2d\n", + name, track_counts[i], peak_counts[i], fail_counts[i]); + } +#else /* COAP_MEMORY_TYPE_TRACK */ + (void)level; +#endif /* COAP_MEMORY_TYPE_TRACK */ +} +#endif /* !WITH_LWIP */ diff --git a/src/coap_net.c b/src/coap_net.c index 355b3f3021..3ba1822b43 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -665,9 +665,7 @@ coap_free_context(coap_context_t *context) { #endif /* COAP_SERVER_SUPPORT */ coap_free_type(COAP_CONTEXT, context); -#ifdef WITH_LWIP - coap_lwip_dump_memory_pools(COAP_LOG_DEBUG); -#endif /* WITH_LWIP */ + coap_dump_memory_type_counts(COAP_LOG_DEBUG); } int