]> granicus.if.org Git - esp-idf/commitdiff
heap: Separate standalone and common part of tracing module
authorAlexey Gerenkov <alexey@espressif.com>
Wed, 12 Dec 2018 17:29:47 +0000 (20:29 +0300)
committerAlexey Gerenkov <alexey@espressif.com>
Mon, 1 Apr 2019 12:56:15 +0000 (15:56 +0300)
components/heap/CMakeLists.txt
components/heap/Kconfig
components/heap/component.mk
components/heap/heap_trace_standalone.c [moved from components/heap/heap_trace.c with 56% similarity]
components/heap/include/esp_heap_trace.h
components/heap/include/heap_trace.inc [new file with mode: 0644]

index 442a9676f1f1ce31aab29c3ec08552e12732aa74..fbbd10eeae828f855ea472d5da8ae29f7e770220 100644 (file)
@@ -1,6 +1,5 @@
 set(COMPONENT_SRCS "heap_caps.c"
                    "heap_caps_init.c"
-                   "heap_trace.c"
                    "multi_heap.c")
 
 if(NOT CONFIG_HEAP_POISONING_DISABLED)
@@ -11,6 +10,10 @@ if(CONFIG_HEAP_TASK_TRACKING)
     list(APPEND COMPONENT_SRCS "heap_task_info.c")
 endif()
 
+if(CONFIG_HEAP_TRACING_STANDALONE)
+    list(APPEND COMPONENT_SRCS "heap_trace_standalone.c")
+endif()
+
 set(COMPONENT_ADD_INCLUDEDIRS "include")
 set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
 set(COMPONENT_REQUIRES "")
index b2e00ab3a07cbd39cb875c36cd30260191692d8b..c0e226bdd26cb58d9c4afce095918081853a04c8 100644 (file)
@@ -17,14 +17,31 @@ menu "Heap memory debugging"
             bool "Comprehensive"
     endchoice
 
-    config HEAP_TRACING
-        bool "Enable heap tracing"
+    choice HEAP_TRACING_DEST
+        bool "Heap tracing"
+        default HEAP_TRACING_OFF
         help
             Enables the heap tracing API defined in esp_heap_trace.h.
 
             This function causes a moderate increase in IRAM code side and a minor increase in heap function
-            (malloc/free/realloc) CPU overhead, even when the tracing feature is not used. So it's best to keep it
-            disabled unless tracing is being used.
+            (malloc/free/realloc) CPU overhead, even when the tracing feature is not used.
+            So it's best to keep it disabled unless tracing is being used.
+
+        config HEAP_TRACING_OFF
+            bool "Disabled"
+        config HEAP_TRACING_STANDALONE
+            bool "Standalone"
+            select HEAP_TRACING
+        config HEAP_TRACING_TOHOST
+            bool "Host-based"
+            select HEAP_TRACING
+    endchoice
+
+    config HEAP_TRACING
+        bool
+        default F
+        help
+            Enables/disables heap tracing API.
 
     config HEAP_TRACING_STACK_DEPTH
         int "Heap tracing stack depth"
index 7d8ef920af786970f2169037f29da51e47fe2e30..266fbada07a0332fa000ae1819b0815360667ade 100644 (file)
@@ -2,7 +2,7 @@
 # Component Makefile
 #
 
-COMPONENT_OBJS := heap_caps_init.o heap_caps.o multi_heap.o heap_trace.o
+COMPONENT_OBJS := heap_caps_init.o heap_caps.o multi_heap.o
 
 ifndef CONFIG_HEAP_POISONING_DISABLED
 COMPONENT_OBJS += multi_heap_poisoning.o
@@ -12,6 +12,12 @@ COMPONENT_OBJS += heap_task_info.o
 endif
 endif
 
+ifdef CONFIG_HEAP_TRACING_STANDALONE
+
+COMPONENT_OBJS += heap_trace_standalone.o
+
+endif
+
 ifdef CONFIG_HEAP_TRACING
 
 WRAP_FUNCTIONS = calloc malloc free realloc heap_caps_malloc heap_caps_free heap_caps_realloc heap_caps_malloc_default heap_caps_realloc_default
similarity index 56%
rename from components/heap/heap_trace.c
rename to components/heap/heap_trace_standalone.c
index 58babbc19e2388e6f52731b1be4eb22773b18620..138a8cd35f537d7d17ac24b59c07552c52de4dc4 100644 (file)
 // See the License for the specific language governing permissions and
 // limitations under the License.
 #include <string.h>
-#include <sys/param.h>
 #include <sdkconfig.h>
 
 #define HEAP_TRACE_SRCFILE /* don't warn on inclusion here */
 #include "esp_heap_trace.h"
 #undef HEAP_TRACE_SRCFILE
 
-#include "esp_heap_caps.h"
 #include "esp_attr.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
-#include "soc/soc_memory_layout.h"
 
-#include "heap_private.h"
 
 #define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
 
+#if CONFIG_HEAP_TRACING_STANDALONE
+
 static portMUX_TYPE trace_mux = portMUX_INITIALIZER_UNLOCKED;
 static bool tracing;
 static heap_trace_mode_t mode;
@@ -55,10 +53,6 @@ static bool has_overflowed = false;
 
 esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records)
 {
-#ifndef CONFIG_HEAP_TRACING
-    return ESP_ERR_NOT_SUPPORTED;
-#endif
-
     if (tracing) {
         return ESP_ERR_INVALID_STATE;
     }
@@ -70,13 +64,10 @@ esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t
 
 esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
 {
-#ifndef CONFIG_HEAP_TRACING
-    return ESP_ERR_NOT_SUPPORTED;
-#endif
-
     if (buffer == NULL || total_records == 0) {
         return ESP_ERR_INVALID_STATE;
     }
+
     portENTER_CRITICAL(&trace_mux);
 
     tracing = false;
@@ -93,9 +84,6 @@ esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
 
 static esp_err_t set_tracing(bool enable)
 {
-#ifndef CONFIG_HEAP_TRACING
-    return ESP_ERR_NOT_SUPPORTED;
-#endif
     if (tracing == enable) {
         return ESP_ERR_INVALID_STATE;
     }
@@ -120,9 +108,6 @@ size_t heap_trace_get_count(void)
 
 esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
 {
-#ifndef CONFIG_HEAP_TRACING
-    return ESP_ERR_NOT_SUPPORTED;
-#endif
     if (record == NULL) {
         return ESP_ERR_INVALID_STATE;
     }
@@ -141,10 +126,6 @@ esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
 
 void heap_trace_dump(void)
 {
-#ifndef CONFIG_HEAP_TRACING
-    printf("no data, heap tracing is disabled.\n");
-    return;
-#endif
     size_t delta_size = 0;
     size_t delta_allocs = 0;
     printf("%u allocations trace (%u entry buffer)\n",
@@ -192,6 +173,10 @@ void heap_trace_dump(void)
 /* Add a new allocation to the heap trace records */
 static IRAM_ATTR void record_allocation(const heap_trace_record_t *record)
 {
+    if (!tracing || record->address == NULL) {
+        return;
+    }
+
     portENTER_CRITICAL(&trace_mux);
     if (tracing) {
         if (count == total_records) {
@@ -224,6 +209,10 @@ static void remove_record(int index);
 */
 static IRAM_ATTR void record_free(void *p, void **callers)
 {
+    if (!tracing || p == NULL) {
+        return;
+    }
+
     portENTER_CRITICAL(&trace_mux);
     if (tracing && count > 0) {
         total_frees++;
@@ -261,179 +250,6 @@ static IRAM_ATTR void remove_record(int index)
     count--;
 }
 
-/* Encode the CPU ID in the LSB of the ccount value */
-inline static uint32_t get_ccount(void)
-{
-    uint32_t ccount = xthal_get_ccount() & ~3;
-#ifndef CONFIG_FREERTOS_UNICORE
-    ccount |= xPortGetCoreID();
-#endif
-    return ccount;
-}
-
-// Caller is 2 stack frames deeper than we care about
-#define STACK_OFFSET  2
-
-#define TEST_STACK(N) do {                                              \
-        if (STACK_DEPTH == N) {                                         \
-            return;                                                     \
-        }                                                               \
-        callers[N] = __builtin_return_address(N+STACK_OFFSET);                \
-        if (!esp_ptr_executable(callers[N])) {                          \
-            return;                                                     \
-        }                                                               \
-    } while(0)
-
-/* Static function to read the call stack for a traced heap call.
-
-   Calls to __builtin_return_address are "unrolled" via TEST_STACK macro as gcc requires the
-   argument to be a compile-time constant.
-*/
-static IRAM_ATTR __attribute__((noinline)) void get_call_stack(void **callers)
-{
-    bzero(callers, sizeof(void *) * STACK_DEPTH);
-    TEST_STACK(0);
-    TEST_STACK(1);
-    TEST_STACK(2);
-    TEST_STACK(3);
-    TEST_STACK(4);
-    TEST_STACK(5);
-    TEST_STACK(6);
-    TEST_STACK(7);
-    TEST_STACK(8);
-    TEST_STACK(9);
-}
-
-_Static_assert(STACK_DEPTH >= 0 && STACK_DEPTH <= 10, "CONFIG_HEAP_TRACING_STACK_DEPTH must be in range 0-10");
-
-
-typedef enum {
-    TRACE_MALLOC_CAPS,
-    TRACE_MALLOC_DEFAULT
-} trace_malloc_mode_t;
-
-
-void *__real_heap_caps_malloc(size_t size, uint32_t caps);
-void *__real_heap_caps_malloc_default( size_t size );
-void *__real_heap_caps_realloc_default( void *ptr, size_t size );
-
-/* trace any 'malloc' event */
-static IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t size, uint32_t caps, trace_malloc_mode_t mode)
-{
-    uint32_t ccount = get_ccount();
-    void *p;
-    if ( mode == TRACE_MALLOC_CAPS ) {
-        p = __real_heap_caps_malloc(size, caps);
-    } else { //TRACE_MALLOC_DEFAULT
-        p = __real_heap_caps_malloc_default(size);
-    }
-
-    if (tracing && p != NULL) {
-        heap_trace_record_t rec = {
-            .address = p,
-            .ccount = ccount,
-            .size = size,
-        };
-        get_call_stack(rec.alloced_by);
-        record_allocation(&rec);
-    }
-    return p;
-}
-
-void __real_heap_caps_free(void *p);
-
-/* trace any 'free' event */
-static IRAM_ATTR __attribute__((noinline)) void trace_free(void *p)
-{
-    if (tracing && p != NULL) {
-        void *callers[STACK_DEPTH];
-        get_call_stack(callers);
-        record_free(p, callers);
-    }
-    __real_heap_caps_free(p);
-}
-
-void * __real_heap_caps_realloc(void *p, size_t size, uint32_t caps);
+#include "heap_trace.inc"
 
-/* trace any 'realloc' event */
-static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t size, uint32_t caps, trace_malloc_mode_t mode)
-{
-    void *callers[STACK_DEPTH];
-    uint32_t ccount = get_ccount();
-    if (tracing && p != NULL && size == 0) {
-        get_call_stack(callers);
-        record_free(p, callers);
-    }
-    void *r;
-    if (mode == TRACE_MALLOC_CAPS ) {
-        r = __real_heap_caps_realloc(p, size, caps);
-    } else { //TRACE_MALLOC_DEFAULT
-        r = __real_heap_caps_realloc_default(p, size);
-    }
-    if (tracing && r != NULL) {
-        get_call_stack(callers);
-        if (p != NULL) {
-            /* trace realloc as free-then-alloc */
-            record_free(p, callers);
-        }
-        heap_trace_record_t rec = {
-            .address = r,
-            .ccount = ccount,
-            .size = size,
-        };
-        memcpy(rec.alloced_by, callers, sizeof(void *) * STACK_DEPTH);
-        record_allocation(&rec);
-    }
-    return r;
-}
-
-/* Note: this changes the behaviour of libc malloc/realloc/free a bit,
-   as they no longer go via the libc functions in ROM. But more or less
-   the same in the end. */
-
-IRAM_ATTR void *__wrap_malloc(size_t size)
-{
-    return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
-}
-
-IRAM_ATTR void __wrap_free(void *p)
-{
-    trace_free(p);
-}
-
-IRAM_ATTR void *__wrap_realloc(void *p, size_t size)
-{
-    return trace_realloc(p, size, 0, TRACE_MALLOC_DEFAULT);
-}
-
-IRAM_ATTR void *__wrap_calloc(size_t nmemb, size_t size)
-{
-    size = size * nmemb;
-    void *result = trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
-    if (result != NULL) {
-        memset(result, 0, size);
-    }
-    return result;
-}
-
-IRAM_ATTR void *__wrap_heap_caps_malloc(size_t size, uint32_t caps)
-{
-    return trace_malloc(size, caps, TRACE_MALLOC_CAPS);
-}
-
-void __wrap_heap_caps_free(void *p) __attribute__((alias("__wrap_free")));
-
-IRAM_ATTR void *__wrap_heap_caps_realloc(void *p, size_t size, uint32_t caps)
-{
-    return trace_realloc(p, size, caps, TRACE_MALLOC_CAPS);
-}
-
-IRAM_ATTR void *__wrap_heap_caps_malloc_default( size_t size )
-{
-    return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
-}
-
-IRAM_ATTR void *__wrap_heap_caps_realloc_default( void *ptr, size_t size )
-{
-    return trace_realloc(ptr, size, 0, TRACE_MALLOC_DEFAULT);
-}
+#endif /*CONFIG_HEAP_TRACING_STANDALONE*/
index 5573d5e5abb387945d2d1d9cf0e197110e2da305..a71f96362c1eeb97ceebd4211f906f65077f53d2 100644 (file)
@@ -47,7 +47,6 @@ typedef struct {
 
 /**
  * @brief Initialise heap tracing in standalone mode.
- * @note Standalone mode is the only mode currently supported.
  *
  * This function must be called before any other heap tracing functions.
  *
@@ -63,6 +62,17 @@ typedef struct {
  */
 esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records);
 
+/**
+ * @brief Initialise heap tracing in host-based mode.
+ *
+ * This function must be called before any other heap tracing functions.
+ *
+ * @return
+ *  - ESP_ERR_INVALID_STATE Heap tracing is currently in progress.
+ *  - ESP_OK Heap tracing initialised successfully.
+ */
+esp_err_t heap_trace_init_tohost(void);
+
 /**
  * @brief Start heap tracing. All heap allocations & frees will be traced, until heap_trace_stop() is called.
  *
diff --git a/components/heap/include/heap_trace.inc b/components/heap/include/heap_trace.inc
new file mode 100644 (file)
index 0000000..a51b07a
--- /dev/null
@@ -0,0 +1,189 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+#include <sdkconfig.h>
+#include "soc/soc_memory_layout.h"
+#include "esp_attr.h"
+
+/* Encode the CPU ID in the LSB of the ccount value */
+inline static uint32_t get_ccount(void)
+{
+    uint32_t ccount = xthal_get_ccount() & ~3;
+#ifndef CONFIG_FREERTOS_UNICORE
+    ccount |= xPortGetCoreID();
+#endif
+    return ccount;
+}
+
+// Caller is 2 stack frames deeper than we care about
+#define STACK_OFFSET  2
+
+#define TEST_STACK(N) do {                                              \
+        if (STACK_DEPTH == N) {                                         \
+            return;                                                     \
+        }                                                               \
+        callers[N] = __builtin_return_address(N+STACK_OFFSET);                \
+        if (!esp_ptr_executable(callers[N])) {                          \
+            return;                                                     \
+        }                                                               \
+    } while(0)
+
+/* Static function to read the call stack for a traced heap call.
+
+   Calls to __builtin_return_address are "unrolled" via TEST_STACK macro as gcc requires the
+   argument to be a compile-time constant.
+*/
+static IRAM_ATTR __attribute__((noinline)) void get_call_stack(void **callers)
+{
+    bzero(callers, sizeof(void *) * STACK_DEPTH);
+    TEST_STACK(0);
+    TEST_STACK(1);
+    TEST_STACK(2);
+    TEST_STACK(3);
+    TEST_STACK(4);
+    TEST_STACK(5);
+    TEST_STACK(6);
+    TEST_STACK(7);
+    TEST_STACK(8);
+    TEST_STACK(9);
+}
+
+_Static_assert(STACK_DEPTH >= 0 && STACK_DEPTH <= 10, "CONFIG_HEAP_TRACING_STACK_DEPTH must be in range 0-10");
+
+
+typedef enum {
+    TRACE_MALLOC_CAPS,
+    TRACE_MALLOC_DEFAULT
+} trace_malloc_mode_t;
+
+
+void *__real_heap_caps_malloc(size_t size, uint32_t caps);
+void *__real_heap_caps_malloc_default( size_t size );
+void *__real_heap_caps_realloc_default( void *ptr, size_t size );
+
+/* trace any 'malloc' event */
+static IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t size, uint32_t caps, trace_malloc_mode_t mode)
+{
+    uint32_t ccount = get_ccount();
+    void *p;
+
+    if ( mode == TRACE_MALLOC_CAPS ) {
+        p = __real_heap_caps_malloc(size, caps);
+    } else { //TRACE_MALLOC_DEFAULT
+        p = __real_heap_caps_malloc_default(size);
+    }
+
+    heap_trace_record_t rec = {
+        .address = p,
+        .ccount = ccount,
+        .size = size,
+    };
+    get_call_stack(rec.alloced_by);
+    record_allocation(&rec);
+    return p;
+}
+
+void __real_heap_caps_free(void *p);
+
+/* trace any 'free' event */
+static IRAM_ATTR __attribute__((noinline)) void trace_free(void *p)
+{
+    void *callers[STACK_DEPTH];
+    get_call_stack(callers);
+    record_free(p, callers);
+
+    __real_heap_caps_free(p);
+}
+
+void * __real_heap_caps_realloc(void *p, size_t size, uint32_t caps);
+
+/* trace any 'realloc' event */
+static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t size, uint32_t caps, trace_malloc_mode_t mode)
+{
+    void *callers[STACK_DEPTH];
+    uint32_t ccount = get_ccount();
+    void *r;
+
+    /* trace realloc as free-then-alloc */
+    get_call_stack(callers);
+    record_free(p, callers);
+
+    if (mode == TRACE_MALLOC_CAPS ) {
+        r = __real_heap_caps_realloc(p, size, caps);
+    } else { //TRACE_MALLOC_DEFAULT
+        r = __real_heap_caps_realloc_default(p, size);
+    }
+    /* realloc with zero size is a free */
+    if (size != 0) {
+        heap_trace_record_t rec = {
+            .address = r,
+            .ccount = ccount,
+            .size = size,
+        };
+        memcpy(rec.alloced_by, callers, sizeof(void *) * STACK_DEPTH);
+        record_allocation(&rec);
+    }
+    return r;
+}
+
+/* Note: this changes the behaviour of libc malloc/realloc/free a bit,
+   as they no longer go via the libc functions in ROM. But more or less
+   the same in the end. */
+
+IRAM_ATTR void *__wrap_malloc(size_t size)
+{
+    return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
+}
+
+IRAM_ATTR void __wrap_free(void *p)
+{
+    trace_free(p);
+}
+
+IRAM_ATTR void *__wrap_realloc(void *p, size_t size)
+{
+    return trace_realloc(p, size, 0, TRACE_MALLOC_DEFAULT);
+}
+
+IRAM_ATTR void *__wrap_calloc(size_t nmemb, size_t size)
+{
+    size = size * nmemb;
+    void *result = trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
+    if (result != NULL) {
+        memset(result, 0, size);
+    }
+    return result;
+}
+
+IRAM_ATTR void *__wrap_heap_caps_malloc(size_t size, uint32_t caps)
+{
+    return trace_malloc(size, caps, TRACE_MALLOC_CAPS);
+}
+
+void __wrap_heap_caps_free(void *p) __attribute__((alias("__wrap_free")));
+
+IRAM_ATTR void *__wrap_heap_caps_realloc(void *p, size_t size, uint32_t caps)
+{
+    return trace_realloc(p, size, caps, TRACE_MALLOC_CAPS);
+}
+
+IRAM_ATTR void *__wrap_heap_caps_malloc_default( size_t size )
+{
+    return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
+}
+
+IRAM_ATTR void *__wrap_heap_caps_realloc_default( void *ptr, size_t size )
+{
+    return trace_realloc(ptr, size, 0, TRACE_MALLOC_DEFAULT);
+}