Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
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 Sun Jul 17 2022 08:25:23 by 1.7.2