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.
Fork of mbed-os by
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 "mbed.h" 00019 #include "rtos.h" 00020 #include "mbed_stats.h" 00021 #include "cmsis_os.h" 00022 #include "greentea-client/test_env.h" 00023 #include "greentea-client/greentea_metrics.h" 00024 #include "SingletonPtr.h" 00025 #include "CircularBuffer.h" 00026 00027 #define THREAD_BUF_COUNT 16 00028 00029 typedef struct { 00030 uint32_t entry; 00031 uint32_t arg; 00032 uint32_t stack_size; 00033 uint32_t max_stack; 00034 } thread_info_t; 00035 00036 // Mutex to protect "buf" 00037 SingletonPtr<Mutex> mutex; 00038 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00039 static char buf[128]; 00040 static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue; 00041 #endif 00042 00043 static void send_heap_info(void); 00044 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00045 static void send_stack_info(void); 00046 static void on_thread_terminate(osThreadId id); 00047 static void enqeue_thread_info(osThreadId id); 00048 static void deque_and_print_thread_info(void); 00049 00050 // sprintf uses a lot of stack so use these instead 00051 static uint32_t print_hex(char *buf, uint32_t value); 00052 static uint32_t print_dec(char *buf, uint32_t value); 00053 #endif 00054 00055 void greentea_metrics_setup() 00056 { 00057 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00058 Thread::attach_terminate_hook(on_thread_terminate); 00059 #endif 00060 } 00061 00062 void greentea_metrics_report() 00063 { 00064 send_heap_info(); 00065 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00066 send_stack_info(); 00067 Thread::attach_terminate_hook(NULL); 00068 #endif 00069 } 00070 00071 static void send_heap_info() 00072 { 00073 mbed_stats_heap_t heap_stats; 00074 mbed_stats_heap_get(&heap_stats); 00075 greentea_send_kv("max_heap_usage",heap_stats.max_size); 00076 } 00077 00078 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00079 MBED_UNUSED static void send_stack_info() 00080 { 00081 mutex->lock(); 00082 00083 // Flush any queued stack entries 00084 while (!queue->empty()) { 00085 deque_and_print_thread_info(); 00086 } 00087 00088 // Print info for all other threads 00089 osThreadEnumId enum_id = _osThreadsEnumStart(); 00090 while (true) { 00091 osThreadId thread_id = _osThreadEnumNext(enum_id); 00092 if (NULL == thread_id) { 00093 // End of enumeration 00094 break; 00095 } 00096 enqeue_thread_info(thread_id); 00097 deque_and_print_thread_info(); 00098 } 00099 _osThreadEnumFree(enum_id); 00100 00101 mutex->unlock(); 00102 } 00103 00104 MBED_UNUSED static void on_thread_terminate(osThreadId id) 00105 { 00106 mutex->lock(); 00107 00108 // There should always be space in the queue 00109 enqeue_thread_info(id); 00110 00111 // If queue is full then print out a single entry 00112 if (queue->full()) { 00113 deque_and_print_thread_info(); 00114 } 00115 00116 mutex->unlock(); 00117 } 00118 00119 static void enqeue_thread_info(osThreadId id) 00120 { 00121 osEvent info; 00122 thread_info_t thread_info = {}; 00123 info = _osThreadGetInfo(id, osThreadInfoEntry); 00124 if (info.status != osOK) { 00125 return; 00126 } 00127 thread_info.entry = (uint32_t)info.value.p; 00128 info = _osThreadGetInfo(id, osThreadInfoArg); 00129 if (info.status != osOK) { 00130 return; 00131 } 00132 thread_info.arg = (uint32_t)info.value.p; 00133 info = _osThreadGetInfo(id, osThreadInfoStackSize); 00134 if (info.status != osOK) { 00135 return; 00136 } 00137 thread_info.stack_size = (uint32_t)info.value.v; 00138 info = _osThreadGetInfo(id, osThreadInfoStackMax); 00139 if (info.status != osOK) { 00140 return; 00141 } 00142 thread_info.max_stack = (uint32_t)info.value.v; 00143 queue->push(thread_info); 00144 } 00145 00146 static void deque_and_print_thread_info() 00147 { 00148 thread_info_t thread_info; 00149 bool ret = queue->pop(thread_info); 00150 MBED_ASSERT(ret); 00151 uint32_t pos = 0; 00152 buf[pos++] = '\"'; 00153 pos += print_hex(buf + pos, thread_info.entry); 00154 buf[pos++] = '-'; 00155 pos += print_hex(buf + pos, thread_info.arg); 00156 buf[pos++] = '\"'; 00157 buf[pos++] = ','; 00158 pos += print_dec(buf + pos, thread_info.max_stack); 00159 buf[pos++] = ','; 00160 pos += print_dec(buf + pos, thread_info.stack_size); 00161 buf[pos++] = 0; 00162 greentea_send_kv("__thread_info", buf); 00163 } 00164 00165 static uint32_t print_hex(char *buf, uint32_t value) 00166 { 00167 uint32_t pos = 0; 00168 buf[pos] = '0'; 00169 pos++; 00170 buf[pos] = 'x'; 00171 pos++; 00172 for (int i = 8; i >= 0; i--) { 00173 uint32_t val = (value >> (4 * i)) & 0xF; 00174 if (val <= 9) { 00175 buf[pos] = '0' + val; 00176 pos++; 00177 } else { 00178 buf[pos] = 'a' + val - 10; 00179 pos++; 00180 } 00181 } 00182 return pos; 00183 } 00184 00185 static uint32_t print_dec(char *buf, uint32_t value) 00186 { 00187 uint32_t pos = 0; 00188 00189 // The value 0 is special case 00190 if (0 == value) { 00191 buf[pos] = '0'; 00192 pos++; 00193 return pos; 00194 } 00195 00196 // Write out value in reverse order 00197 while (value != 0) { 00198 uint32_t next = value / 10; 00199 buf[pos] = '0' + (value - next * 10); 00200 value = next; 00201 pos++; 00202 } 00203 00204 // Reverse order 00205 for (uint32_t i = 0; i < pos / 2; i++) { 00206 char temp = buf[i]; 00207 buf[i] = buf[pos - 1 - i]; 00208 buf[pos - 1 - i] = temp; 00209 } 00210 00211 return pos; 00212 } 00213 00214 #endif
Generated on Tue Jul 12 2022 13:15:50 by
