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