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.
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 #define THREAD_BUF_COUNT 16 00024 00025 typedef struct { 00026 uint32_t entry; 00027 uint32_t stack_size; 00028 uint32_t max_stack; 00029 } thread_info_t; 00030 00031 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00032 00033 #if !defined(MBED_CONF_RTOS_PRESENT) || !(MBED_CONF_RTOS_PRESENT) 00034 #error "RTOS required for Stack stats" 00035 #endif 00036 00037 #include "rtos/Mutex.h" 00038 #include "rtos/Thread.h" 00039 #include "rtos/Kernel.h" 00040 #include "mbed_stats.h" 00041 #include "cmsis_os2.h" 00042 #include "platform/SingletonPtr.h" 00043 #include "platform/CircularBuffer.h" 00044 using namespace mbed; 00045 using namespace rtos; 00046 00047 // Mutex to protect "buf" 00048 static SingletonPtr<Mutex> mutex; 00049 static char buf[128]; 00050 static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue; 00051 #endif 00052 00053 #if defined(MBED_CPU_STATS_ENABLED) 00054 static void send_CPU_info(void); 00055 #endif 00056 00057 #if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED 00058 static void send_heap_info(void); 00059 #endif 00060 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00061 static void send_stack_info(void); 00062 static void on_thread_terminate(osThreadId_t id); 00063 static void enqeue_thread_info(osThreadId_t id); 00064 static void deque_and_print_thread_info(void); 00065 00066 // sprintf uses a lot of stack so use these instead 00067 static uint32_t print_hex(char *buf, uint32_t value); 00068 static uint32_t print_dec(char *buf, uint32_t value); 00069 #endif 00070 00071 void greentea_metrics_setup() 00072 { 00073 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00074 Thread::attach_terminate_hook(on_thread_terminate); 00075 #endif 00076 } 00077 00078 void greentea_metrics_report() 00079 { 00080 #if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED 00081 send_heap_info(); 00082 #endif 00083 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00084 send_stack_info(); 00085 Thread::attach_terminate_hook(NULL); 00086 #endif 00087 #if defined(MBED_CPU_STATS_ENABLED) 00088 send_CPU_info(); 00089 #endif 00090 } 00091 00092 #if defined(MBED_CPU_STATS_ENABLED) 00093 static void send_CPU_info() 00094 { 00095 mbed_stats_cpu_t stats; 00096 mbed_stats_cpu_get(&stats); 00097 00098 greentea_send_kv("__cpu_info up time", stats.uptime); 00099 greentea_send_kv("__cpu_info sleep time", stats.sleep_time); 00100 greentea_send_kv("__cpu_info deepsleep time", stats.deep_sleep_time); 00101 greentea_send_kv("__cpu_info % sleep/deep", (stats.sleep_time * 100) / stats.uptime, (stats.deep_sleep_time * 100) / stats.uptime); 00102 } 00103 #endif 00104 00105 #if defined(MBED_HEAP_STATS_ENABLED ) && MBED_HEAP_STATS_ENABLED 00106 static void send_heap_info() 00107 { 00108 mbed_stats_heap_t heap_stats; 00109 mbed_stats_heap_get(&heap_stats); 00110 greentea_send_kv("max_heap_usage",heap_stats.max_size); 00111 greentea_send_kv("reserved_heap",heap_stats.reserved_size); 00112 } 00113 #endif 00114 00115 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00116 MBED_UNUSED static void send_stack_info() 00117 { 00118 mutex->lock(); 00119 00120 // Flush any queued stack entries 00121 while (!queue->empty()) { 00122 deque_and_print_thread_info(); 00123 } 00124 00125 // Print info for all other threads 00126 uint32_t thread_n = osThreadGetCount(); 00127 osThreadId_t *threads = new (std::nothrow) osThreadId_t[thread_n]; 00128 // Don't fail on lack of memory 00129 if (!threads) { 00130 goto end; 00131 } 00132 thread_n = osThreadEnumerate(threads, thread_n); 00133 00134 for(size_t i = 0; i < thread_n; i++) { 00135 enqeue_thread_info(threads[i]); 00136 deque_and_print_thread_info(); 00137 } 00138 00139 delete[] threads; 00140 00141 end: 00142 mutex->unlock(); 00143 } 00144 00145 MBED_UNUSED static void on_thread_terminate(osThreadId_t id) 00146 { 00147 mutex->lock(); 00148 00149 // There should always be space in the queue 00150 enqeue_thread_info(id); 00151 00152 // If queue is full then print out a single entry 00153 if (queue->full()) { 00154 deque_and_print_thread_info(); 00155 } 00156 00157 mutex->unlock(); 00158 } 00159 00160 static void enqeue_thread_info(osThreadId_t id) 00161 { 00162 thread_info_t thread_info = {}; 00163 00164 thread_info.entry = (uint32_t)id; 00165 thread_info.stack_size = osThreadGetStackSize(id); 00166 thread_info.max_stack = thread_info.stack_size - osThreadGetStackSpace(id); 00167 queue->push(thread_info); 00168 } 00169 00170 static void deque_and_print_thread_info() 00171 { 00172 thread_info_t thread_info; 00173 bool ret = queue->pop(thread_info); 00174 MBED_ASSERT(ret); 00175 uint32_t pos = 0; 00176 buf[pos++] = '\"'; 00177 pos += print_hex(buf + pos, thread_info.entry); 00178 buf[pos++] = '\"'; 00179 buf[pos++] = ','; 00180 pos += print_dec(buf + pos, thread_info.max_stack); 00181 buf[pos++] = ','; 00182 pos += print_dec(buf + pos, thread_info.stack_size); 00183 buf[pos++] = 0; 00184 greentea_send_kv("__thread_info", buf); 00185 } 00186 00187 static uint32_t print_hex(char *buf, uint32_t value) 00188 { 00189 uint32_t pos = 0; 00190 buf[pos] = '0'; 00191 pos++; 00192 buf[pos] = 'x'; 00193 pos++; 00194 for (int i = 8; i >= 0; i--) { 00195 uint32_t val = (value >> (4 * i)) & 0xF; 00196 if (val <= 9) { 00197 buf[pos] = '0' + val; 00198 pos++; 00199 } else { 00200 buf[pos] = 'a' + val - 10; 00201 pos++; 00202 } 00203 } 00204 return pos; 00205 } 00206 00207 static uint32_t print_dec(char *buf, uint32_t value) 00208 { 00209 uint32_t pos = 0; 00210 00211 // The value 0 is special case 00212 if (0 == value) { 00213 buf[pos] = '0'; 00214 pos++; 00215 return pos; 00216 } 00217 00218 // Write out value in reverse order 00219 while (value != 0) { 00220 uint32_t next = value / 10; 00221 buf[pos] = '0' + (value - next * 10); 00222 value = next; 00223 pos++; 00224 } 00225 00226 // Reverse order 00227 for (uint32_t i = 0; i < pos / 2; i++) { 00228 char temp = buf[i]; 00229 buf[i] = buf[pos - 1 - i]; 00230 buf[pos - 1 - i] = temp; 00231 } 00232 00233 return pos; 00234 } 00235 00236 #endif
Generated on Tue Jul 12 2022 20:52:44 by
1.7.2