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 OmniWheels 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_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 static void send_heap_info(void); 00043 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00044 static void send_stack_info(void); 00045 static void on_thread_terminate(osThreadId_t id); 00046 static void enqeue_thread_info(osThreadId_t id); 00047 static void deque_and_print_thread_info(void); 00048 00049 // sprintf uses a lot of stack so use these instead 00050 static uint32_t print_hex(char *buf, uint32_t value); 00051 static uint32_t print_dec(char *buf, uint32_t value); 00052 #endif 00053 00054 void greentea_metrics_setup() 00055 { 00056 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00057 Thread::attach_terminate_hook(on_thread_terminate); 00058 #endif 00059 } 00060 00061 void greentea_metrics_report() 00062 { 00063 send_heap_info(); 00064 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED 00065 send_stack_info(); 00066 Thread::attach_terminate_hook(NULL); 00067 #endif 00068 } 00069 00070 static void send_heap_info() 00071 { 00072 mbed_stats_heap_t heap_stats; 00073 mbed_stats_heap_get(&heap_stats); 00074 greentea_send_kv("max_heap_usage",heap_stats.max_size); 00075 greentea_send_kv("reserved_heap",heap_stats.reserved_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 uint32_t thread_n = osThreadGetCount(); 00090 osThreadId_t *threads = new osThreadId_t[thread_n]; 00091 thread_n = osThreadEnumerate(threads, thread_n); 00092 00093 for(size_t i = 0; i < thread_n; i++) { 00094 enqeue_thread_info(threads[i]); 00095 deque_and_print_thread_info(); 00096 } 00097 00098 delete[] threads; 00099 00100 mutex->unlock(); 00101 } 00102 00103 MBED_UNUSED static void on_thread_terminate(osThreadId_t id) 00104 { 00105 mutex->lock(); 00106 00107 // There should always be space in the queue 00108 enqeue_thread_info(id); 00109 00110 // If queue is full then print out a single entry 00111 if (queue->full()) { 00112 deque_and_print_thread_info(); 00113 } 00114 00115 mutex->unlock(); 00116 } 00117 00118 static void enqeue_thread_info(osThreadId_t id) 00119 { 00120 thread_info_t thread_info = {}; 00121 00122 thread_info.entry = (uint32_t)id; 00123 thread_info.stack_size = osThreadGetStackSize(id); 00124 thread_info.max_stack = thread_info.stack_size - osThreadGetStackSpace(id); 00125 queue->push(thread_info); 00126 } 00127 00128 static void deque_and_print_thread_info() 00129 { 00130 thread_info_t thread_info; 00131 bool ret = queue->pop(thread_info); 00132 MBED_ASSERT(ret); 00133 uint32_t pos = 0; 00134 buf[pos++] = '\"'; 00135 pos += print_hex(buf + pos, thread_info.entry); 00136 buf[pos++] = '\"'; 00137 buf[pos++] = ','; 00138 pos += print_dec(buf + pos, thread_info.max_stack); 00139 buf[pos++] = ','; 00140 pos += print_dec(buf + pos, thread_info.stack_size); 00141 buf[pos++] = 0; 00142 greentea_send_kv("__thread_info", buf); 00143 } 00144 00145 static uint32_t print_hex(char *buf, uint32_t value) 00146 { 00147 uint32_t pos = 0; 00148 buf[pos] = '0'; 00149 pos++; 00150 buf[pos] = 'x'; 00151 pos++; 00152 for (int i = 8; i >= 0; i--) { 00153 uint32_t val = (value >> (4 * i)) & 0xF; 00154 if (val <= 9) { 00155 buf[pos] = '0' + val; 00156 pos++; 00157 } else { 00158 buf[pos] = 'a' + val - 10; 00159 pos++; 00160 } 00161 } 00162 return pos; 00163 } 00164 00165 static uint32_t print_dec(char *buf, uint32_t value) 00166 { 00167 uint32_t pos = 0; 00168 00169 // The value 0 is special case 00170 if (0 == value) { 00171 buf[pos] = '0'; 00172 pos++; 00173 return pos; 00174 } 00175 00176 // Write out value in reverse order 00177 while (value != 0) { 00178 uint32_t next = value / 10; 00179 buf[pos] = '0' + (value - next * 10); 00180 value = next; 00181 pos++; 00182 } 00183 00184 // Reverse order 00185 for (uint32_t i = 0; i < pos / 2; i++) { 00186 char temp = buf[i]; 00187 buf[i] = buf[pos - 1 - i]; 00188 buf[pos - 1 - i] = temp; 00189 } 00190 00191 return pos; 00192 } 00193 00194 #endif
Generated on Fri Jul 22 2022 04:53:50 by
1.7.2
