diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9964d85abd0..591b0b31568 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,7 @@ set(CORE_SRCS
   cores/esp32/esp32-hal-uart.c
   cores/esp32/esp32-hal-rmt.c
   cores/esp32/Esp.cpp
+  cores/esp32/freertos_stats.cpp
   cores/esp32/FunctionalInterrupt.cpp
   cores/esp32/HardwareSerial.cpp
   cores/esp32/HEXBuilder.cpp
diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h
index 2b115505cff..ab7e497dcf6 100644
--- a/cores/esp32/Arduino.h
+++ b/cores/esp32/Arduino.h
@@ -199,6 +199,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
 #include "Udp.h"
 #include "HardwareSerial.h"
 #include "Esp.h"
+#include "freertos_stats.h"
 
 // Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries
 using std::abs;
diff --git a/cores/esp32/freertos_stats.cpp b/cores/esp32/freertos_stats.cpp
new file mode 100644
index 00000000000..50a98bf502b
--- /dev/null
+++ b/cores/esp32/freertos_stats.cpp
@@ -0,0 +1,111 @@
+// Copyright 2024 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 "freertos_stats.h"
+#include "sdkconfig.h"
+
+#if CONFIG_FREERTOS_USE_TRACE_FACILITY
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/portable.h"
+#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */
+
+void printRunningTasks(Print &printer) {
+#if CONFIG_FREERTOS_USE_TRACE_FACILITY
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+#define FREERTOS_TASK_NUMBER_MAX_NUM 256  // RunTime stats for how many Tasks to be stored
+  static configRUN_TIME_COUNTER_TYPE ulRunTimeCounters[FREERTOS_TASK_NUMBER_MAX_NUM];
+  static configRUN_TIME_COUNTER_TYPE ulLastRunTime = 0;
+  configRUN_TIME_COUNTER_TYPE ulCurrentRunTime = 0, ulTaskRunTime = 0;
+#endif
+  configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0;
+  TaskStatus_t *pxTaskStatusArray = NULL;
+  volatile UBaseType_t uxArraySize = 0, x = 0;
+  const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"};
+
+  // Take a snapshot of the number of tasks in case it changes while this function is executing.
+  uxArraySize = uxTaskGetNumberOfTasks();
+
+  // Allocate a TaskStatus_t structure for each task.
+  pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));
+
+  if (pxTaskStatusArray != NULL) {
+    // Generate raw status information about each task.
+    uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime);
+
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+    ulCurrentRunTime = ulTotalRunTime - ulLastRunTime;
+    ulLastRunTime = ulTotalRunTime;
+#endif
+    printer.printf(
+      "Tasks: %u"
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+      ", Runtime: %lus, Period: %luus"
+#endif
+      "\n",
+      uxArraySize
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+      ,
+      ulTotalRunTime / 1000000, ulCurrentRunTime
+#endif
+    );
+    printer.printf("Num\t            Name"
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+                   "\tLoad"
+#endif
+                   "\tPrio\t Free"
+#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
+                   "\tCore"
+#endif
+                   "\tState\r\n");
+    for (x = 0; x < uxArraySize; x++) {
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+      if (pxTaskStatusArray[x].xTaskNumber < FREERTOS_TASK_NUMBER_MAX_NUM) {
+        ulTaskRunTime = (pxTaskStatusArray[x].ulRunTimeCounter - ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber]);
+        ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber] = pxTaskStatusArray[x].ulRunTimeCounter;
+        ulTaskRunTime = (ulTaskRunTime * 100) / ulCurrentRunTime;  // in percentage
+      } else {
+        ulTaskRunTime = 0;
+      }
+#endif
+      printer.printf(
+        "%3u\t%16s"
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+        "\t%3lu%%"
+#endif
+        "\t%4u\t%5lu"
+#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
+        "\t%4c"
+#endif
+        "\t%s\r\n",
+        pxTaskStatusArray[x].xTaskNumber, pxTaskStatusArray[x].pcTaskName,
+#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+        ulTaskRunTime,
+#endif
+        pxTaskStatusArray[x].uxCurrentPriority, pxTaskStatusArray[x].usStackHighWaterMark,
+#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID
+        (pxTaskStatusArray[x].xCoreID == tskNO_AFFINITY) ? '*' : ('0' + pxTaskStatusArray[x].xCoreID),
+#endif
+        taskStates[pxTaskStatusArray[x].eCurrentState]
+      );
+    }
+
+    // The array is no longer needed, free the memory it consumes.
+    vPortFree(pxTaskStatusArray);
+    printer.println();
+  }
+#else
+  printer.println("FreeRTOS trace facility is not enabled.");
+#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */
+}
diff --git a/cores/esp32/freertos_stats.h b/cores/esp32/freertos_stats.h
new file mode 100644
index 00000000000..ea9e1a55a21
--- /dev/null
+++ b/cores/esp32/freertos_stats.h
@@ -0,0 +1,28 @@
+// Copyright 2024 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.
+
+#pragma once
+
+#ifdef __cplusplus
+
+#include "Print.h"
+
+/*
+ * Executing this function will cause interrupts and
+ * the scheduler to be blocked for some time.
+ * Please use only for debugging purposes.
+ */
+void printRunningTasks(Print &printer);
+
+#endif