From df80f7505910be2ff53013715c93a889507be5f6 Mon Sep 17 00:00:00 2001 From: Jiacheng Guo Date: Thu, 27 May 2021 20:05:55 +0800 Subject: [PATCH] [esp32] add heap trace extension for esp32 --- .../esp32/main/CMakeLists.txt | 2 + examples/all-clusters-app/esp32/main/main.cpp | 17 +- examples/lock-app/esp32/main/CMakeLists.txt | 2 + examples/lock-app/esp32/main/main.cpp | 6 + .../esp32/shell_extension/heap_trace.cpp | 150 ++++++++++++++++++ .../esp32/shell_extension/heap_trace.h | 26 +++ .../platform/esp32/shell_extension/launch.cpp | 48 ++++++ .../platform/esp32/shell_extension/launch.h | 26 +++ 8 files changed, 265 insertions(+), 12 deletions(-) create mode 100644 examples/platform/esp32/shell_extension/heap_trace.cpp create mode 100644 examples/platform/esp32/shell_extension/heap_trace.h create mode 100644 examples/platform/esp32/shell_extension/launch.cpp create mode 100644 examples/platform/esp32/shell_extension/launch.h diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index b7a7c49b6227d4..99a47db25bd314 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -19,12 +19,14 @@ # The list of src and include dirs must be in sync with that in all-clusters-app/esp32/main/component.mk idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/third_party/nlio/repo/include" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src" "${CMAKE_CURRENT_LIST_DIR}/include" SRC_DIRS "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/gen" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/shell_extension" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/test-cluster-server" diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index 35d5e2c8ae9611..6796f80cff6fa7 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -35,6 +35,7 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "nvs_flash.h" +#include "shell_extension/launch.h" #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -546,13 +546,6 @@ class AppCallbacks : public AppDelegate void OnPairingWindowClosed() override { pairingWindowLED.Set(false); } }; -#if CONFIG_ENABLE_CHIP_SHELL -void ChipShellTask(void * args) -{ - chip::Shell::Engine::Root().RunMainLoop(); -} -#endif // CONFIG_ENABLE_CHIP_SHELL - } // namespace extern "C" void app_main() @@ -586,6 +579,10 @@ extern "C" void app_main() return; } +#if CONFIG_ENABLE_CHIP_SHELL + idf::chip::LaunchShell(); +#endif // CONFIG_ENABLE_CHIP_SHELL + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); err = deviceMgr.Init(&EchoCallbacks); @@ -607,10 +604,6 @@ extern "C" void app_main() AppCallbacks callbacks; InitServer(&callbacks); -#if CONFIG_ENABLE_CHIP_SHELL - xTaskCreate(&ChipShellTask, "chip_shell", 2048, NULL, 5, NULL); -#endif - SetupPretendDevices(); std::string qrCodeText = createSetupPayload(); diff --git a/examples/lock-app/esp32/main/CMakeLists.txt b/examples/lock-app/esp32/main/CMakeLists.txt index a73629a3b31d54..8372f215bb825a 100644 --- a/examples/lock-app/esp32/main/CMakeLists.txt +++ b/examples/lock-app/esp32/main/CMakeLists.txt @@ -18,10 +18,12 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/lock-app/lock-common" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32" "${CMAKE_CURRENT_LIST_DIR}/include" SRC_DIRS "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/lock-app/lock-common/gen" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/platform/esp32/shell_extension" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/util" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/reporting" diff --git a/examples/lock-app/esp32/main/main.cpp b/examples/lock-app/esp32/main/main.cpp index e65cf0ef05253e..672b88088991b7 100644 --- a/examples/lock-app/esp32/main/main.cpp +++ b/examples/lock-app/esp32/main/main.cpp @@ -27,6 +27,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "nvs_flash.h" +#include "shell_extension/heap_trace.h" +#include "shell_extension/launch.h" #include #include @@ -58,6 +60,10 @@ extern "C" void app_main() ESP_LOGI(TAG, "chip-esp32-lock-example starting"); ESP_LOGI(TAG, "=================================================="); +#if CONFIG_ENABLE_CHIP_SHELL + idf::chip::LaunchShell(); +#endif + CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance(); err = deviceMgr.Init(&EchoCallbacks); diff --git a/examples/platform/esp32/shell_extension/heap_trace.cpp b/examples/platform/esp32/shell_extension/heap_trace.cpp new file mode 100644 index 00000000000000..2014ebf9dc62e6 --- /dev/null +++ b/examples/platform/esp32/shell_extension/heap_trace.cpp @@ -0,0 +1,150 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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 "heap_trace.h" + +#include + +#include +#include +#include +#include +#include + +#include "esp_err.h" +#include "esp_heap_caps.h" +#include "esp_heap_task_info.h" +#include "esp_heap_trace.h" + +using chip::Shell::Engine; +using chip::Shell::PrintCommandHelp; +using chip::Shell::shell_command_t; +using chip::Shell::streamer_get; +using chip::Shell::streamer_printf; + +namespace { + +constexpr size_t kNumHeapTraceRecords = 100; +constexpr size_t kNumHeapTasks = 20; +constexpr size_t kNumHeapBlocks = 20; + +heap_trace_record_t sTraceRecords[kNumHeapTraceRecords]; + +Engine sShellHeapSubCommands; + +int HeapTraceHelpHandler(int argc, char ** argv) +{ + sShellHeapSubCommands.ForEachCommand(PrintCommandHelp, nullptr); + return 0; +} + +#if CONFIG_HEAP_TRACING_STANDALONE +int HeapTraceResetHandler(int argc, char ** argv) +{ + ESP_ERROR_CHECK(heap_trace_stop()); + ESP_ERROR_CHECK(heap_trace_start(HEAP_TRACE_LEAKS)); + return 0; +} + +int HeapTraceDumpHandler(int argc, char ** argv) +{ + heap_trace_dump(); + streamer_printf(streamer_get(), "Free heap %d/%d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_total_size(MALLOC_CAP_8BIT)); + return 0; +} +#endif // CONFIG_HEAP_TRACING_STANDALONE + +#if CONFIG_HEAP_TASK_TRACKING +int HeapTraceTaskHandler(int argc, char ** argv) +{ + // static storage is required for task memory info; + static size_t numTotals = 0; + static heap_task_totals_t sTotals[kNumHeapTasks]; + static heap_task_block_t sBlocks[kNumHeapBlocks]; + + heap_task_info_params_t heap_info; + memset(&heap_info, 0, sizeof(heap_info)); + heap_info.caps[0] = MALLOC_CAP_8BIT; // Gets heap with CAP_8BIT capabilities + heap_info.mask[0] = MALLOC_CAP_8BIT; + heap_info.caps[1] = MALLOC_CAP_32BIT; // Gets heap info with CAP_32BIT capabilities + heap_info.mask[1] = MALLOC_CAP_32BIT; + heap_info.tasks = NULL; // Passing NULL captures heap info for all tasks + heap_info.num_tasks = 0; + heap_info.totals = sTotals; // Gets task wise allocation details + heap_info.num_totals = &numTotals; + heap_info.max_totals = kNumHeapTasks; // Maximum length of "sTotals" + heap_info.blocks = sBlocks; // Gets block wise allocation details. For each block, gets owner task, address and size + heap_info.max_blocks = kNumHeapBlocks; // Maximum length of "sBlocks" + + heap_caps_get_per_task_info(&heap_info); + + for (int i = 0; i < *heap_info.num_totals; i++) + { + streamer_printf(streamer_get(), "Task: %s -> CAP_8BIT: %zu CAP_32BIT: %zu\n", + heap_info.totals[i].task ? pcTaskGetTaskName(heap_info.totals[i].task) : "Pre-Scheduler allocs", + heap_info.totals[i].size[0], // Heap size with CAP_8BIT capabilities + heap_info.totals[i].size[1]); // Heap size with CAP32_BIT capabilities + } + streamer_printf(streamer_get(), "Free heap %d/%d\n", heap_caps_get_free_size(MALLOC_CAP_8BIT), + heap_caps_get_total_size(MALLOC_CAP_8BIT)); + + return 0; +} +#endif + +int HeapTraceDispatch(int argc, char ** argv) +{ + if (argc == 0) + { + HeapTraceHelpHandler(argc, argv); + return CHIP_NO_ERROR; + } + + return sShellHeapSubCommands.ExecCommand(argc, argv); +} + +} // namespace + +namespace idf { +namespace chip { + +void RegisterHeapTraceCommands() +{ + static const shell_command_t sHeapSubCommands[] = { + { &HeapTraceHelpHandler, "help", "Usage: heap-trace " }, +#if CONFIG_HEAP_TRACING_STANDALONE + { &HeapTraceResetHandler, "reset", "Reset the heap trace baseline" }, + { &HeapTraceDumpHandler, "dump", "Dump the last collected heap trace" }, +#endif // CONFIG_HEAP_TRACING_STANDALONE +#if CONFIG_HEAP_TASK_TRACKING + { &HeapTraceTaskHandler, "task", "Dump heap usage of each task" }, +#endif // CONFIG_HEAP_TASK_TRACKING + }; + sShellHeapSubCommands.RegisterCommands(sHeapSubCommands, ArraySize(sHeapSubCommands)); + +#if CONFIG_HEAP_TRACING_STANDALONE + ESP_ERROR_CHECK(heap_trace_init_standalone(sTraceRecords, kNumHeapTraceRecords)); + ESP_ERROR_CHECK(heap_trace_start(HEAP_TRACE_LEAKS)); +#endif // CONFIG_HEAP_TRACING_STANDALONE + + static const shell_command_t sHeapCommand = { &HeapTraceDispatch, "heap-trace", "Heap debug tracing" }; + Engine::Root().RegisterCommands(&sHeapCommand, 1); +} + +} // namespace chip +} // namespace idf diff --git a/examples/platform/esp32/shell_extension/heap_trace.h b/examples/platform/esp32/shell_extension/heap_trace.h new file mode 100644 index 00000000000000..59e92551ee9c97 --- /dev/null +++ b/examples/platform/esp32/shell_extension/heap_trace.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#pragma once + +namespace idf { +namespace chip { + +void RegisterHeapTraceCommands(); + +} +} // namespace idf diff --git a/examples/platform/esp32/shell_extension/launch.cpp b/examples/platform/esp32/shell_extension/launch.cpp new file mode 100644 index 00000000000000..e5576d5041ef8b --- /dev/null +++ b/examples/platform/esp32/shell_extension/launch.cpp @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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 "launch.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "heap_trace.h" +#include "sdkconfig.h" + +#include + +namespace { + +void MatterShellTask(void * args) +{ + chip::Shell::Engine::Root().RunMainLoop(); +} + +} // namespace + +namespace idf { +namespace chip { + +void LaunchShell() +{ +#if CONFIG_HEAP_TRACING_STANDALONE || CONFIG_HEAP_TASK_TRACKING + RegisterHeapTraceCommands(); +#endif // CONFIG_HEAP_TRACING_STANDALONE || CONFIG_HEAP_TASK_TRACKING + xTaskCreate(&MatterShellTask, "chip_cli", 2048, NULL, 5, NULL); +} + +} // namespace chip +} // namespace idf diff --git a/examples/platform/esp32/shell_extension/launch.h b/examples/platform/esp32/shell_extension/launch.h new file mode 100644 index 00000000000000..34df8ea1e22c3e --- /dev/null +++ b/examples/platform/esp32/shell_extension/launch.h @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * 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. + */ + +#pragma once + +namespace idf { +namespace chip { + +void LaunchShell(); + +} +} // namespace idf