Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
greentea_metrics.cpp
00001 /* 00002 * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "greentea-client/test_env.h" 00019 #include "greentea-client/greentea_metrics.h" 00020 #include "platform/mbed_stats.h" 00021 #include <stdint.h> 00022 00023 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00024 00025 #include "rtos/Mutex.h" 00026 #include "rtos/Thread.h" 00027 #include "rtos/Kernel.h" 00028 #include "mbed_stats.h" 00029 #include "cmsis_os2.h" 00030 #include "platform/SingletonPtr.h" 00031 #include "platform/CircularBuffer.h" 00032 using namespace mbed; 00033 using namespace rtos; 00034 00035 #define THREAD_BUF_COUNT 16 00036 00037 typedef struct { 00038 uint32_t entry; 00039 uint32_t stack_size; 00040 uint32_t max_stack; 00041 } thread_info_t; 00042 00043 // Mutex to protect "buf" 00044 static SingletonPtr<Mutex> mutex; 00045 static char buf[128]; 00046 static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue; 00047 #endif 00048 00049 #if defined(MBED_CPU_STATS_ENABLED) 00050 static void send_CPU_info(void); 00051 #endif 00052 00053 #if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED 00054 static void send_heap_info(void); 00055 #endif 00056 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00057 static void send_stack_info(void); 00058 static void on_thread_terminate(osThreadId_t id); 00059 static void enqeue_thread_info(osThreadId_t id); 00060 static void deque_and_print_thread_info(void); 00061 00062 // sprintf uses a lot of stack so use these instead 00063 static uint32_t print_hex(char *buf, uint32_t value); 00064 static uint32_t print_dec(char *buf, uint32_t value); 00065 #endif 00066 00067 void greentea_metrics_setup() 00068 { 00069 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00070 Kernel::attach_thread_terminate_hook(on_thread_terminate); 00071 #endif 00072 } 00073 00074 void greentea_metrics_report() 00075 { 00076 #if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED 00077 send_heap_info(); 00078 #endif 00079 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00080 send_stack_info(); 00081 Kernel::attach_thread_terminate_hook(NULL); 00082 #endif 00083 #if defined(MBED_CPU_STATS_ENABLED) 00084 send_CPU_info(); 00085 #endif 00086 } 00087 00088 #if defined(MBED_CPU_STATS_ENABLED) 00089 static void send_CPU_info() 00090 { 00091 mbed_stats_cpu_t stats; 00092 mbed_stats_cpu_get(&stats); 00093 00094 greentea_send_kv("__cpu_info up time", stats.uptime); 00095 greentea_send_kv("__cpu_info sleep time", stats.sleep_time); 00096 greentea_send_kv("__cpu_info deepsleep time", stats.deep_sleep_time); 00097 greentea_send_kv("__cpu_info % sleep/deep", (stats.sleep_time * 100) / stats.uptime, (stats.deep_sleep_time * 100) / stats.uptime); 00098 } 00099 #endif 00100 00101 #if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED 00102 static void send_heap_info() 00103 { 00104 mbed_stats_heap_t heap_stats; 00105 mbed_stats_heap_get(&heap_stats); 00106 greentea_send_kv("max_heap_usage",heap_stats.max_size); 00107 greentea_send_kv("reserved_heap",heap_stats.reserved_size); 00108 } 00109 #endif 00110 00111 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED && defined(MBED_CONF_RTOS_PRESENT) 00112 MBED_UNUSED static void send_stack_info() 00113 { 00114 mutex->lock(); 00115 00116 // Flush any queued stack entries 00117 while (!queue->empty()) { 00118 deque_and_print_thread_info(); 00119 } 00120 00121 // Print info for all other threads 00122 uint32_t thread_n = osThreadGetCount(); 00123 osThreadId_t *threads = new (std::nothrow) osThreadId_t[thread_n]; 00124 // Don't fail on lack of memory 00125 if (!threads) { 00126 goto end; 00127 } 00128 thread_n = osThreadEnumerate(threads, thread_n); 00129 00130 for(size_t i = 0; i < thread_n; i++) { 00131 enqeue_thread_info(threads[i]); 00132 deque_and_print_thread_info(); 00133 } 00134 00135 delete[] threads; 00136 00137 end: 00138 mutex->unlock(); 00139 } 00140 00141 MBED_UNUSED static void on_thread_terminate(osThreadId_t id) 00142 { 00143 mutex->lock(); 00144 00145 // There should always be space in the queue 00146 enqeue_thread_info(id); 00147 00148 // If queue is full then print out a single entry 00149 if (queue->full()) { 00150 deque_and_print_thread_info(); 00151 } 00152 00153 mutex->unlock(); 00154 } 00155 00156 static void enqeue_thread_info(osThreadId_t id) 00157 { 00158 thread_info_t thread_info = {}; 00159 00160 thread_info.entry = (uint32_t)id; 00161 thread_info.stack_size = osThreadGetStackSize(id); 00162 thread_info.max_stack = thread_info.stack_size - osThreadGetStackSpace(id); 00163 queue->push(thread_info); 00164 } 00165 00166 static void deque_and_print_thread_info() 00167 { 00168 thread_info_t thread_info; 00169 bool ret = queue->pop(thread_info); 00170 MBED_ASSERT(ret); 00171 uint32_t pos = 0; 00172 buf[pos++] = '\"'; 00173 pos += print_hex(buf + pos, thread_info.entry); 00174 buf[pos++] = '\"'; 00175 buf[pos++] = ','; 00176 pos += print_dec(buf + pos, thread_info.max_stack); 00177 buf[pos++] = ','; 00178 pos += print_dec(buf + pos, thread_info.stack_size); 00179 buf[pos++] = 0; 00180 greentea_send_kv("__thread_info", buf); 00181 } 00182 00183 static uint32_t print_hex(char *buf, uint32_t value) 00184 { 00185 uint32_t pos = 0; 00186 buf[pos] = '0'; 00187 pos++; 00188 buf[pos] = 'x'; 00189 pos++; 00190 for (int i = 8; i >= 0; i--) { 00191 uint32_t val = (value >> (4 * i)) & 0xF; 00192 if (val <= 9) { 00193 buf[pos] = '0' + val; 00194 pos++; 00195 } else { 00196 buf[pos] = 'a' + val - 10; 00197 pos++; 00198 } 00199 } 00200 return pos; 00201 } 00202 00203 static uint32_t print_dec(char *buf, uint32_t value) 00204 { 00205 uint32_t pos = 0; 00206 00207 // The value 0 is special case 00208 if (0 == value) { 00209 buf[pos] = '0'; 00210 pos++; 00211 return pos; 00212 } 00213 00214 // Write out value in reverse order 00215 while (value != 0) { 00216 uint32_t next = value / 10; 00217 buf[pos] = '0' + (value - next * 10); 00218 value = next; 00219 pos++; 00220 } 00221 00222 // Reverse order 00223 for (uint32_t i = 0; i < pos / 2; i++) { 00224 char temp = buf[i]; 00225 buf[i] = buf[pos - 1 - i]; 00226 buf[pos - 1 - i] = temp; 00227 } 00228 00229 return pos; 00230 } 00231 00232 #endif
Generated on Tue Jul 12 2022 13:54:24 by
