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: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
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 static 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 11:02:39 by
