diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt index 61920102605cba..f927d770709279 100644 --- a/config/esp32/components/chip/CMakeLists.txt +++ b/config/esp32/components/chip/CMakeLists.txt @@ -264,6 +264,10 @@ if (CONFIG_ENABLE_ESP_INSIGHTS_TRACE) chip_gn_arg_append("matter_enable_esp_insights_trace" "true") endif() +if (CONFIG_ENABLE_ESP_INSIGHTS_SYSTEM_STATS) + chip_gn_arg_append("matter_enable_esp_insights_system_stats" "true") +endif() + if (CONFIG_USE_ESP32_ECDSA_PERIPHERAL) chip_gn_arg_append("chip_use_esp32_ecdsa_peripheral" "true") endif() diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index 3c099437ad9813..86786b96cf4326 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -818,6 +818,12 @@ menu "CHIP Device Layer" Enabling the above option will enable the esp32 specific tracing functionality and report the diagnostic information to the insights cloud. + config ENABLE_ESP_INSIGHTS_SYSTEM_STATS + bool "Enable System Stats for insights" + depends on ESP_INSIGHTS_ENABLED + default n + help + This option enables the system statistics to be sent to the insights cloud. endmenu diff --git a/examples/lighting-app/esp32/main/main.cpp b/examples/lighting-app/esp32/main/main.cpp index 79247258658dd8..9ca27f30414553 100644 --- a/examples/lighting-app/esp32/main/main.cpp +++ b/examples/lighting-app/esp32/main/main.cpp @@ -39,6 +39,10 @@ #include #include +#if CONFIG_ENABLE_ESP_INSIGHTS_SYSTEM_STATS +#include +#endif + #if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER #include #endif // CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER @@ -113,6 +117,25 @@ static void InitServer(intptr_t context) DeviceCallbacksDelegate::Instance().SetAppDelegate(&sAppDeviceCallbacksDelegate); Esp32AppServer::Init(); // Init ZCL Data Model and CHIP App Server AND Initialize device attestation config + +#if CONFIG_ENABLE_ESP_INSIGHTS_TRACE + esp_insights_config_t config = { + .log_type = ESP_DIAG_LOG_TYPE_ERROR | ESP_DIAG_LOG_TYPE_WARNING | ESP_DIAG_LOG_TYPE_EVENT, + .auth_key = insights_auth_key_start, + }; + + esp_err_t ret = esp_insights_init(&config); + + if (ret != ESP_OK) + { + ESP_LOGE(TAG, "Failed to initialize ESP Insights, err:0x%x", ret); + } + +// Setting the sampling time to 30 seconds i.e 30,000 ms +#if CONFIG_ENABLE_ESP_INSIGHTS_SYSTEM_STATS + chip::System::Stats::InsightsSystemMetrics::GetInstance().RegisterAndEnable(chip::System::Clock::Timeout(60000)); +#endif +#endif } extern "C" void app_main() @@ -134,20 +157,6 @@ extern "C" void app_main() chip::rpc::Init(); #endif -#if CONFIG_ENABLE_ESP_INSIGHTS_TRACE - esp_insights_config_t config = { - .log_type = ESP_DIAG_LOG_TYPE_ERROR | ESP_DIAG_LOG_TYPE_WARNING | ESP_DIAG_LOG_TYPE_EVENT, - .auth_key = insights_auth_key_start, - }; - - esp_err_t ret = esp_insights_init(&config); - - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to initialize ESP Insights, err:0x%x", ret); - } -#endif - ESP_LOGI(TAG, "=================================================="); ESP_LOGI(TAG, "chip-esp32-light-example starting"); ESP_LOGI(TAG, "=================================================="); diff --git a/src/tracing/esp32_trace/BUILD.gn b/src/tracing/esp32_trace/BUILD.gn index d7580a3e68ac2a..5eb0807fbdd47c 100644 --- a/src/tracing/esp32_trace/BUILD.gn +++ b/src/tracing/esp32_trace/BUILD.gn @@ -19,9 +19,21 @@ import("//build_overrides/chip.gni") config("tracing") { include_dirs = [ "include" ] } - +declare_args() { + matter_enable_esp_insights_system_stats = false +} source_set("esp32_trace") { public = [ "include/matter/tracing/macros_impl.h" ] sources = [ "include/matter/tracing/macros_impl.cpp" ] public_configs = [ ":tracing" ] + + if (matter_enable_esp_insights_system_stats) { + public += [ "include/matter/tracing/insights_sys_stats.h" ] + sources += [ "include/matter/tracing/insights_sys_stats.cpp" ] + deps = [ + "${chip_root}/src/lib/core", + "${chip_root}/src/platform", + "${chip_root}/src/system", + ] + } } diff --git a/src/tracing/esp32_trace/include/matter/tracing/insights_sys_stats.cpp b/src/tracing/esp32_trace/include/matter/tracing/insights_sys_stats.cpp new file mode 100644 index 00000000000000..7f987bea2f62b5 --- /dev/null +++ b/src/tracing/esp32_trace/include/matter/tracing/insights_sys_stats.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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 "insights_sys_stats.h" +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace System { +namespace Stats { + +InsightsSystemMetrics & InsightsSystemMetrics::GetInstance() +{ + static InsightsSystemMetrics instance; + return instance; +} + +void InsightsSystemMetrics::StartTimerCallback(Layer * systemLayer, void * context) +{ + auto instance = static_cast(context); + count_t * highwatermarks = GetHighWatermarks(); + for (int i = 0; i < System::Stats::kNumEntries; i++) + { + esp_err_t err = esp_diag_metrics_add_uint(instance->mLabels[i], static_cast(highwatermarks[i])); + if (err != ESP_OK) + { + ESP_LOGE(kTag, "Failed to add the metric:%s, err:%d", instance->mLabels[i], err); + } + } + DeviceLayer::SystemLayer().StartTimer(instance->GetTimeout(), StartTimerCallback, instance); +} + +CHIP_ERROR InsightsSystemMetrics::Unregister() +{ + if (!mRegistered) + { + return CHIP_ERROR_INCORRECT_STATE; + } + for (int i = 0; i < System::Stats::kNumEntries; i++) + { + if (mLabels[i] != nullptr) + { + esp_err_t err = esp_diag_metrics_unregister(mLabels[i]); + if (err != ESP_OK) + { + ESP_LOGE(kTag, "Failed to unregister metric:%s, err:%d", mLabels[i], err); + } + free(mLabels[i]); + mLabels[i] = nullptr; + } + } + return CHIP_NO_ERROR; +} + +void InsightsSystemMetrics::CancelTimeout(intptr_t arg) +{ + auto instance = static_cast(reinterpret_cast(arg)); + instance->_CancelTimeout(); +} + +void InsightsSystemMetrics::_CancelTimeout() +{ + DeviceLayer::SystemLayer().CancelTimer(StartTimerCallback, this); +} + +CHIP_ERROR InsightsSystemMetrics::SetTimeout(chip::System::Clock::Timeout aTimeout) +{ + if (!mRegistered) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + if (aTimeout == System::Clock::kZero) + { + DeviceLayer::PlatformMgr().ScheduleWork(CancelTimeout, reinterpret_cast(this)); + } + else if (aTimeout != mTimeout) + { + DeviceLayer::PlatformMgr().ScheduleWork(CancelTimeout, reinterpret_cast(this)); + mTimeout = aTimeout; + CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(mTimeout, StartTimerCallback, this); + if (err != CHIP_NO_ERROR) + { + ESP_LOGE(kTag, "Failed to start the new timer %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR InsightsSystemMetrics::RegisterAndEnable(chip::System::Clock::Timeout aTimeout) +{ + if (mRegistered) + { + return CHIP_NO_ERROR; + } + + if (aTimeout == System::Clock::kZero) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + const Label * labels = GetStrings(); + for (int i = 0; i < System::Stats::kNumEntries; i++) + { + size_t labelLength = strlen(labels[i]); + if (labelLength >= kMaxStringLength) + { + labelLength = kMaxStringLength; + mLabels[i] = strndup(labels[i], labelLength - 1); + } + else + { + mLabels[i] = strndup(labels[i], labelLength); + } + + if (mLabels[i] == NULL) + { + Unregister(); + return CHIP_ERROR_NO_MEMORY; + } + + esp_err_t err = esp_diag_metrics_register(kTag, mLabels[i], labels[i], kPath, ESP_DIAG_DATA_TYPE_UINT); + if (err != ESP_OK) + { + ESP_LOGE(kTag, "Failed to register metric:%s, err:%d", mLabels[i], err); + return CHIP_ERROR_INCORRECT_STATE; + } + } + + mTimeout = System::Clock::Milliseconds32(aTimeout); + + CHIP_ERROR err = DeviceLayer::SystemLayer().StartTimer(GetTimeout(), StartTimerCallback, this); + if (err != CHIP_NO_ERROR) + { + ESP_LOGE(kTag, "Failed to start the timer, err:%" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + mRegistered = true; + return CHIP_NO_ERROR; +} + +} // namespace Stats +} // namespace System +} // namespace chip diff --git a/src/tracing/esp32_trace/include/matter/tracing/insights_sys_stats.h b/src/tracing/esp32_trace/include/matter/tracing/insights_sys_stats.h new file mode 100644 index 00000000000000..dc531d7ce99eac --- /dev/null +++ b/src/tracing/esp32_trace/include/matter/tracing/insights_sys_stats.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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 +#include +#include +#include +namespace chip { +namespace System { +namespace Stats { + +class InsightsSystemMetrics +{ +public: + static InsightsSystemMetrics & GetInstance(); + + /* + * This api registers the system metrics to the insights and starts the + * timer to enable system stats periodically to the insights. + */ + CHIP_ERROR RegisterAndEnable(chip::System::Clock::Timeout aTimeout); + + /* + * This api unregisters the system stats which are registered + * as metrics to the esp-insights. + */ + CHIP_ERROR Unregister(); + + /* + * This api cancels the timeout providing the user the flexibility + * to increase or decrease the frequency of sampling the System + * Stats. It cancels the timer if new timeout value is zero. + * If the value of timeout differs from existing value, then + * it cancels the previous timer and starts a new timer. + */ + CHIP_ERROR SetTimeout(chip::System::Clock::Timeout aTimeout); + + void _CancelTimeout(); + + System::Clock::Timeout GetTimeout() { return mTimeout; } + +private: + InsightsSystemMetrics() {} + static constexpr int kMaxStringLength = 16; + bool mRegistered = false; + static constexpr char kPath[] = "sys.mtr"; + static constexpr char kTag[] = "MTR"; + System::Clock::Timeout mTimeout; + char * mLabels[chip::System::Stats::kNumEntries]; + + static void StartTimerCallback(System::Layer * systemLayer, void * context); + static void CancelTimeout(intptr_t arg); +}; + +} // namespace Stats +} // namespace System +} // namespace chip