]> granicus.if.org Git - esp-idf/commitdiff
sys_view: Adds heap tracing API
authorAlexey Gerenkov <alexey@espressif.com>
Wed, 12 Dec 2018 17:35:17 +0000 (20:35 +0300)
committerAlexey Gerenkov <alexey@espressif.com>
Mon, 1 Apr 2019 16:31:27 +0000 (19:31 +0300)
13 files changed:
components/app_trace/CMakeLists.txt
components/app_trace/Kconfig
components/app_trace/component.mk
components/app_trace/heap_trace_tohost.c [new file with mode: 0644]
components/app_trace/include/esp_sysview_trace.h [new file with mode: 0644]
components/app_trace/linker.lf
components/app_trace/sys_view/SEGGER/SEGGER_RTT.h
components/app_trace/sys_view/SEGGER/SEGGER_SYSVIEW.c
components/app_trace/sys_view/SEGGER/SEGGER_SYSVIEW.h
components/app_trace/sys_view/esp32/SEGGER_RTT_esp32.c
components/app_trace/sys_view/ext/heap_trace_module.c [new file with mode: 0644]
components/app_trace/sys_view/ext/logging.c [new file with mode: 0644]
examples/system/sysview_tracing/main/sysview_tracing.c

index c1b3537ca694b4fafd1f0e0cfca3cfc9851f5fd9..46ab5930d1b907fe859d2d640128e1174bd8ed20 100644 (file)
@@ -13,11 +13,17 @@ if(CONFIG_SYSVIEW_ENABLE)
     list(APPEND COMPONENT_SRCS "sys_view/SEGGER/SEGGER_SYSVIEW.c"
                    "sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c"
                    "sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.c"
-                   "sys_view/esp32/SEGGER_RTT_esp32.c")
+                   "sys_view/esp32/SEGGER_RTT_esp32.c"
+                   "sys_view/ext/heap_trace_module.c"
+                   "sys_view/ext/logging.c")
+endif()
+
+if(CONFIG_HEAP_TRACING_TOHOST)
+    list(APPEND COMPONENT_SRCS "heap_trace_tohost.c")
 endif()
 
 set(COMPONENT_REQUIRES)
-set(COMPONENT_PRIV_REQUIRES)
+set(COMPONENT_PRIV_REQUIRES heap)
 set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
 
 register_component()
index 064f9cf7c005a53aafd5d9cb7aaa147957eb706e..67387c6615f2a30308e853f21e5ab7a297200119 100644 (file)
@@ -107,6 +107,14 @@ menu "Application Level Tracing"
             help
                 Configures maximum supported tasks in sysview debug
 
+        config SYSVIEW_BUF_WAIT_TMO
+            int "Trace buffer wait timeout"
+            depends on SYSVIEW_ENABLE
+            default 500
+            help
+                Configures timeout (in us) to wait for free space in trace buffer.
+                Set to -1 to wait forever and avoid lost events.
+
         config SYSVIEW_EVT_OVERFLOW_ENABLE
             bool "Trace Buffer Overflow Event"
             depends on SYSVIEW_ENABLE
index 384a04a7684de17d691d19be2c0e23bded76a156..a17fa814f052166fda4ce6a20551a939ae593cbe 100644 (file)
@@ -23,7 +23,8 @@ COMPONENT_SRCDIRS += \
        sys_view/SEGGER \
        sys_view/Sample/OS \
        sys_view/Sample/Config \
-       sys_view/esp32
+       sys_view/esp32 \
+       sys_view/ext
 else
 COMPONENT_SRCDIRS += gcov
 endif
diff --git a/components/app_trace/heap_trace_tohost.c b/components/app_trace/heap_trace_tohost.c
new file mode 100644 (file)
index 0000000..764022a
--- /dev/null
@@ -0,0 +1,114 @@
+// Copyright 2018 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 <sdkconfig.h>
+
+#define HEAP_TRACE_SRCFILE /* don't warn on inclusion here */
+#include "esp_heap_trace.h"
+#undef HEAP_TRACE_SRCFILE
+
+#if CONFIG_SYSVIEW_ENABLE
+#include "esp_app_trace.h"
+#include "esp_sysview_trace.h"
+#endif
+
+#define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
+
+#ifdef CONFIG_HEAP_TRACING_TOHOST
+
+#if !CONFIG_SYSVIEW_ENABLE
+#error None of the heap tracing backends is enabled! You must enable SystemView compatible tracing to use this feature.
+#endif
+
+static bool s_tracing;
+
+esp_err_t heap_trace_init_tohost()
+{
+    if (s_tracing) {
+        return ESP_ERR_INVALID_STATE;
+    }
+    return ESP_OK;
+}
+
+esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
+{
+#if CONFIG_SYSVIEW_ENABLE
+    esp_err_t ret = esp_sysview_heap_trace_start((uint32_t)-1);
+    if (ret != ESP_OK) {
+        return ret;
+    }
+#endif
+    s_tracing = true;
+    return ESP_OK;
+}
+
+esp_err_t heap_trace_stop(void)
+{
+    esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
+#if CONFIG_SYSVIEW_ENABLE
+    ret = esp_sysview_heap_trace_stop();
+#endif
+    s_tracing = false;
+    return ret;
+}
+
+esp_err_t heap_trace_resume(void)
+{
+    return heap_trace_start(HEAP_TRACE_ALL);
+}
+
+size_t heap_trace_get_count(void)
+{
+    return 0;
+}
+
+esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
+{
+    return ESP_ERR_NOT_SUPPORTED;
+}
+
+void heap_trace_dump(void)
+{
+    return;
+}
+
+/* Add a new allocation to the heap trace records */
+static IRAM_ATTR void record_allocation(const heap_trace_record_t *record)
+{
+    if (!s_tracing) {
+        return;
+    }
+#if CONFIG_SYSVIEW_ENABLE
+    esp_sysview_heap_trace_alloc(record->address, record->size, record->alloced_by);
+#endif
+}
+
+/* record a free event in the heap trace log
+
+   For HEAP_TRACE_ALL, this means filling in the freed_by pointer.
+   For HEAP_TRACE_LEAKS, this means removing the record from the log.
+*/
+static IRAM_ATTR void record_free(void *p, void **callers)
+{
+    if (!s_tracing) {
+        return;
+    }
+#if CONFIG_SYSVIEW_ENABLE
+    esp_sysview_heap_trace_free(p, callers);
+#endif
+}
+
+#include "heap_trace.inc"
+
+#endif /*CONFIG_HEAP_TRACING_TOHOST*/
+
diff --git a/components/app_trace/include/esp_sysview_trace.h b/components/app_trace/include/esp_sysview_trace.h
new file mode 100644 (file)
index 0000000..3cf04f1
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2018 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.
+#ifndef ESP_SYSVIEW_TRACE_H_
+#define ESP_SYSVIEW_TRACE_H_
+
+#include <stdarg.h>
+#include "esp_err.h"
+#include "SEGGER_RTT.h" // SEGGER_RTT_ESP32_Flush
+#include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE
+
+/**
+ * @brief Flushes remaining data in SystemView trace buffer to host.
+ *
+ * @param tmo  Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
+ *
+ * @return ESP_OK.
+ */
+static inline esp_err_t esp_sysview_flush(uint32_t tmo)
+{
+    SEGGER_RTT_ESP32_Flush(0, tmo);
+    return ESP_OK;
+}
+
+/**
+ * @brief vprintf-like function to sent log messages to the host.
+ *
+ * @param format  Address of format string.
+ * @param args    List of arguments.
+ *
+ * @return Number of bytes written.
+ */
+int esp_sysview_vprintf(const char * format, va_list args);
+
+/**
+ * @brief  Starts SystemView heap tracing.
+ *
+ * @param tmo Timeout (in us) to wait for the host to be connected. Use -1 to wait forever.
+ *
+ * @return ESP_OK on success, ESP_ERR_TIMEOUT if operation has been timed out.
+ */
+esp_err_t esp_sysview_heap_trace_start(uint32_t tmo);
+
+/**
+ * @brief  Stops SystemView heap tracing.
+ *
+ * @return ESP_OK.
+ */
+esp_err_t esp_sysview_heap_trace_stop(void);
+
+/**
+ * @brief Sends heap allocation event to the host.
+ *
+ * @param addr      Address of allocated block.
+ * @param size      Size of allocated block.
+ * @param callers   Pointer to array with callstack addresses.
+ *                  Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.
+ */
+void esp_sysview_heap_trace_alloc(void *addr, uint32_t size, const void *callers);
+
+/**
+ * @brief Sends heap de-allocation event to the host.
+ *
+ * @param addr      Address of de-allocated block.
+ * @param callers   Pointer to array with callstack addresses.
+ *                  Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.
+ */
+void esp_sysview_heap_trace_free(void *addr, const void *callers);
+
+#endif //ESP_SYSVIEW_TRACE_H_
index 5494afc00c74aa7b62e38b2aff52e6ca23e39589..a109829953274f3e4bf027c2d74d51fa027e7074 100644 (file)
@@ -1,7 +1,12 @@
 [mapping]
 archive: libapp_trace.a
 entries: 
-    * (noflash)
+    app_trace (noflash)
+    app_trace_util (noflash)
+    SEGGER_SYSVIEW (noflash)
+    SEGGER_RTT_esp32 (noflash)
+    SEGGER_SYSVIEW_Config_FreeRTOS (noflash)
+    SEGGER_SYSVIEW_FreeRTOS (noflash)
 
 [mapping]
 archive: libdriver.a
index a4673f5aad52264cf3d7c83a940f9b7c86305147..877d6ee331f320d4e88390d9064c92bcef0c6645 100644 (file)
@@ -160,6 +160,7 @@ unsigned     SEGGER_RTT_WriteSkipNoLock         (unsigned BufferIndex, const voi
 unsigned     SEGGER_RTT_WriteString             (unsigned BufferIndex, const char* s);
 void         SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
 void         SEGGER_RTT_ESP32_FlushNoLock       (unsigned long min_sz, unsigned long tmo);
+void         SEGGER_RTT_ESP32_Flush             (unsigned long min_sz, unsigned long tmo);
 //
 // Function macro for performance optimization
 //
index e0d48aca28238c8f70898c927b1bc5f6ec878136..bc21811cc31718a940c2fa2e972a1f33d89f6033 100644 (file)
@@ -1689,6 +1689,10 @@ void SEGGER_SYSVIEW_Stop(void) {
   RECORD_END();
 }
 
+U8 SEGGER_SYSVIEW_Started(void) {
+    return _SYSVIEW_Globals.EnableState;
+}
+
 /*********************************************************************
 *
 *       SEGGER_SYSVIEW_GetSysDesc()
@@ -2678,7 +2682,7 @@ void SEGGER_SYSVIEW_ErrorfTarget(const char* s, ...) {
 void SEGGER_SYSVIEW_Print(const char* s) {
   U8* pPayload;
   U8* pPayloadStart;
-  RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN);
+  RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN + 3/*1 or 3 bytes for string length*/);
   //
   pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);
   ENCODE_U32(pPayload, SEGGER_SYSVIEW_LOG);
index 91cc0c6f4d078513979f6108eed69a3b9b0b3b51..b5b5519d08fbbdab5dc360b805ab9bfdd9131037 100644 (file)
@@ -230,6 +230,8 @@ void SEGGER_SYSVIEW_GetSysDesc                    (void);
 void SEGGER_SYSVIEW_SendTaskList                  (void);
 void SEGGER_SYSVIEW_SendTaskInfo                  (const SEGGER_SYSVIEW_TASKINFO* pInfo);
 void SEGGER_SYSVIEW_SendSysDesc                   (const char* sSysDesc);
+// Checks whether tracing has been started
+U8 SEGGER_SYSVIEW_Started(void);
 
 /*********************************************************************
 *
index 410f303a3f5614cda23a49066a065c72ddd4da91..2ee0a49500536ee5381a2549a926cdca3aec33c0 100644 (file)
@@ -16,6 +16,7 @@
 #include "freertos/FreeRTOS.h"
 #include "SEGGER_RTT.h"
 #include "SEGGER_SYSVIEW.h"
+#include "SEGGER_SYSVIEW_Conf.h"
 
 #include "esp32/rom/ets_sys.h"
 #include "esp_app_trace.h"
@@ -27,8 +28,12 @@ const static char *TAG = "segger_rtt";
 
 // size of down channel data buf
 #define SYSVIEW_DOWN_BUF_SIZE   32
-#define SEGGER_HOST_WAIT_TMO    500 //us
 #define SEGGER_STOP_WAIT_TMO    1000000 //us
+#if CONFIG_SYSVIEW_BUF_WAIT_TMO == -1
+#define SEGGER_HOST_WAIT_TMO    ESP_APPTRACE_TMO_INFINITE
+#else
+#define SEGGER_HOST_WAIT_TMO    CONFIG_SYSVIEW_BUF_WAIT_TMO
+#endif
 
 static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];
 static uint16_t s_events_buf_filled;
@@ -57,9 +62,12 @@ static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE];
 */
 void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
 {
-    esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, tmo);
-    if (res != ESP_OK) {
-      ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res);
+    esp_err_t res;
+    if (s_events_buf_filled > 0) {
+      res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, tmo);
+      if (res != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res);
+      }
     }
     // flush even if we failed to write buffered events, because no new events will be sent after STOP
     res = esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, min_sz, tmo);
@@ -69,6 +77,27 @@ void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
     s_events_buf_filled = 0;
 }
 
+/*********************************************************************
+*
+*       SEGGER_RTT_ESP32_Flush()
+*
+*  Function description
+*    Flushes buffered events.
+*
+*  Parameters
+*    min_sz  Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
+*    tmo     Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
+*
+*  Return value
+*    None.
+*/
+void SEGGER_RTT_ESP32_Flush(unsigned long min_sz, unsigned long tmo)
+{
+    SEGGER_SYSVIEW_LOCK();
+    SEGGER_RTT_ESP32_FlushNoLock(min_sz, tmo);
+    SEGGER_SYSVIEW_UNLOCK();
+}
+
 /*********************************************************************
 *
 *       SEGGER_RTT_ReadNoLock()
diff --git a/components/app_trace/sys_view/ext/heap_trace_module.c b/components/app_trace/sys_view/ext/heap_trace_module.c
new file mode 100644 (file)
index 0000000..3d86f2e
--- /dev/null
@@ -0,0 +1,100 @@
+// Copyright 2018 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 <stdint.h>
+#include <sdkconfig.h>
+#include "SEGGER_SYSVIEW.h"
+#include "SEGGER_RTT.h"
+#include "esp_app_trace.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include "esp_log.h"
+const static char *TAG = "sysview_heap_trace";
+
+#ifdef CONFIG_HEAP_TRACING_STACK_DEPTH
+#define CALLSTACK_SIZE  CONFIG_HEAP_TRACING_STACK_DEPTH
+#else
+#define CALLSTACK_SIZE  0
+#endif
+
+static SEGGER_SYSVIEW_MODULE s_esp_sysview_heap_module = {
+    .sModule = "ESP32 SystemView Heap Tracing Module",
+    .NumEvents = 2,
+};
+
+static bool s_mod_registered;
+
+
+esp_err_t esp_sysview_heap_trace_start(uint32_t tmo)
+{
+    uint32_t tmo_ticks = tmo/(1000*portTICK_PERIOD_MS);
+
+    ESP_EARLY_LOGV(TAG, "%s", __func__);
+    do {
+        if (tmo != (uint32_t)-1) {
+            // Currently timeout implementation is simple and has granularity of 1 OS tick,
+            // so just count down the number of times to call vTaskDelay
+            if (tmo_ticks-- == 0) {
+                return ESP_ERR_TIMEOUT;
+            }
+        }
+        vTaskDelay(1);
+    } while(!SEGGER_SYSVIEW_Started());
+
+    SEGGER_SYSVIEW_RegisterModule(&s_esp_sysview_heap_module);
+    s_mod_registered = true;
+    return ESP_OK;
+}
+
+esp_err_t esp_sysview_heap_trace_stop(void)
+{
+    ESP_EARLY_LOGV(TAG, "%s", __func__);
+    SEGGER_RTT_ESP32_Flush(0, ESP_APPTRACE_TMO_INFINITE);
+    return ESP_OK;
+}
+
+void esp_sysview_heap_trace_alloc(const void *addr, uint32_t size, const void *callers)
+{
+    U8  aPacket[SEGGER_SYSVIEW_INFO_SIZE + (2+CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];
+    U8* pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
+    U32 *calls = (U32 *)callers;
+
+    if (!s_mod_registered) {
+        return;
+    }
+    ESP_EARLY_LOGV(TAG, "%s %p %lu", __func__, addr, size);
+    pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);
+    pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, size);
+    for (int i = 0; i < CALLSTACK_SIZE; i++) {
+        pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);
+    }
+    SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 0);
+}
+
+void esp_sysview_heap_trace_free(const void *addr, const void *callers)
+{
+    U8  aPacket[SEGGER_SYSVIEW_INFO_SIZE + (1+CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];
+    U8* pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
+    U32 *calls = (U32 *)callers;
+
+    if (!s_mod_registered) {
+        return;
+    }
+    ESP_EARLY_LOGV(TAG, "%s %p", __func__, addr);
+    pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);
+    for (int i = 0; i < CALLSTACK_SIZE; i++) {
+        pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);
+    }
+    SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 1);
+}
diff --git a/components/app_trace/sys_view/ext/logging.c b/components/app_trace/sys_view/ext/logging.c
new file mode 100644 (file)
index 0000000..b7aa5ff
--- /dev/null
@@ -0,0 +1,34 @@
+// Copyright 2018 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 <stdio.h>
+#include <stdarg.h>
+#include <sdkconfig.h>
+#include "SEGGER_SYSVIEW_Int.h"
+#include "freertos/FreeRTOS.h"
+
+static portMUX_TYPE s_log_mutex = portMUX_INITIALIZER_UNLOCKED;
+
+int esp_sysview_vprintf(const char * format, va_list args)
+{
+    static char log_buffer[SEGGER_SYSVIEW_MAX_STRING_LEN];
+
+    portENTER_CRITICAL(&s_log_mutex);
+    size_t len = vsnprintf(log_buffer, sizeof(log_buffer), format, args);
+    if (len > sizeof(log_buffer) - 1) {
+        log_buffer[sizeof(log_buffer - 1)] = 0;
+    }
+    SEGGER_SYSVIEW_Print(log_buffer);
+    portEXIT_CRITICAL(&s_log_mutex);
+    return len;
+}
index 3ac03d8da098bbefcc351fedcfea3313a1f611f1..c422d9e46a9c33d3d6572b35fd789ef2b077dc65 100644 (file)
@@ -198,9 +198,12 @@ void app_main()
 
 #if CONFIG_SYSVIEW_ENABLE && CONFIG_USE_CUSTOM_EVENT_ID
     // Currently OpenOCD does not support requesting module info from target. So do the following...
-    // Give SystemView tracing module some time to handle START command from host,
-    // after that data can be sent to the host using onboard API, so user module description does not need to be requested by OpenOCD itself.
-    vTaskDelay(1);
+    // Wait untill SystemView module receives START command from host,
+    // after that data can be sent to the host using onboard API,
+    // so user module description does not need to be requested by OpenOCD itself.
+    while(!SEGGER_SYSVIEW_Started()) {
+        vTaskDelay(1);
+    }
     SEGGER_SYSVIEW_RegisterModule(&s_example_sysview_module);
 #endif