Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers greentea_metrics.cpp Source File

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