ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

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_os.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 arg;
00032     uint32_t stack_size;
00033     uint32_t max_stack;
00034 } thread_info_t;
00035 
00036 // Mutex to protect "buf"
00037 static SingletonPtr<Mutex> mutex;
00038 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED
00039 static char buf[128];
00040 static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue;
00041 #endif
00042 
00043 static void send_heap_info(void);
00044 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED
00045 static void send_stack_info(void);
00046 static void on_thread_terminate(osThreadId id);
00047 static void enqeue_thread_info(osThreadId id);
00048 static void deque_and_print_thread_info(void);
00049 
00050 // sprintf uses a lot of stack so use these instead
00051 static uint32_t print_hex(char *buf, uint32_t value);
00052 static uint32_t print_dec(char *buf, uint32_t value);
00053 #endif
00054 
00055 void greentea_metrics_setup()
00056 {
00057 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED
00058     Thread::attach_terminate_hook(on_thread_terminate);
00059 #endif
00060 }
00061 
00062 void greentea_metrics_report()
00063 {
00064     send_heap_info();
00065 #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED
00066     send_stack_info();
00067     Thread::attach_terminate_hook(NULL);
00068 #endif
00069 }
00070 
00071 static void send_heap_info()
00072 {
00073     mbed_stats_heap_t heap_stats;
00074     mbed_stats_heap_get(&heap_stats);
00075     greentea_send_kv("max_heap_usage",heap_stats.max_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     osThreadEnumId enum_id = _osThreadsEnumStart();
00090     while (true) {
00091         osThreadId thread_id = _osThreadEnumNext(enum_id);
00092         if (NULL == thread_id) {
00093             // End of enumeration
00094             break;
00095         }
00096         enqeue_thread_info(thread_id);
00097         deque_and_print_thread_info();
00098     }
00099     _osThreadEnumFree(enum_id);
00100 
00101     mutex->unlock();
00102 }
00103 
00104 MBED_UNUSED static void on_thread_terminate(osThreadId id)
00105 {
00106     mutex->lock();
00107 
00108     // There should always be space in the queue
00109     enqeue_thread_info(id);
00110 
00111     // If queue is full then print out a single entry
00112     if (queue->full()) {
00113         deque_and_print_thread_info();
00114     }
00115 
00116     mutex->unlock();
00117 }
00118 
00119 static void enqeue_thread_info(osThreadId id)
00120 {
00121     osEvent info;
00122     thread_info_t thread_info = {};
00123     info = _osThreadGetInfo(id, osThreadInfoEntry);
00124     if (info.status != osOK) {
00125         return;
00126     }
00127     thread_info.entry = (uint32_t)info.value.p;
00128     info = _osThreadGetInfo(id, osThreadInfoArg);
00129     if (info.status != osOK) {
00130         return;
00131     }
00132     thread_info.arg = (uint32_t)info.value.p;
00133     info = _osThreadGetInfo(id, osThreadInfoStackSize);
00134     if (info.status != osOK) {
00135         return;
00136     }
00137     thread_info.stack_size = (uint32_t)info.value.v;
00138     info = _osThreadGetInfo(id, osThreadInfoStackMax);
00139     if (info.status != osOK) {
00140         return;
00141     }
00142     thread_info.max_stack = (uint32_t)info.value.v;
00143     queue->push(thread_info);
00144 }
00145 
00146 static void deque_and_print_thread_info()
00147 {
00148     thread_info_t thread_info;
00149     bool ret = queue->pop(thread_info);
00150     MBED_ASSERT(ret);
00151     uint32_t pos = 0;
00152     buf[pos++] = '\"';
00153     pos += print_hex(buf + pos, thread_info.entry);
00154     buf[pos++] = '-';
00155     pos += print_hex(buf + pos, thread_info.arg);
00156     buf[pos++] = '\"';
00157     buf[pos++] = ',';
00158     pos += print_dec(buf + pos, thread_info.max_stack);
00159     buf[pos++] = ',';
00160     pos += print_dec(buf + pos, thread_info.stack_size);
00161     buf[pos++] = 0;
00162     greentea_send_kv("__thread_info", buf);
00163 }
00164 
00165 static uint32_t print_hex(char *buf, uint32_t value)
00166 {
00167     uint32_t pos = 0;
00168     buf[pos] = '0';
00169     pos++;
00170     buf[pos] = 'x';
00171     pos++;
00172     for (int i = 8; i >= 0; i--) {
00173         uint32_t val = (value >> (4 * i)) & 0xF;
00174         if (val <= 9) {
00175             buf[pos] = '0' + val;
00176             pos++;
00177         } else {
00178             buf[pos] = 'a' + val - 10;
00179             pos++;
00180         }
00181     }
00182     return pos;
00183 }
00184 
00185 static uint32_t print_dec(char *buf, uint32_t value)
00186 {
00187     uint32_t pos = 0;
00188 
00189     // The value 0 is special case
00190     if (0 == value) {
00191         buf[pos] = '0';
00192         pos++;
00193         return pos;
00194     }
00195 
00196     // Write out value in reverse order
00197     while (value != 0) {
00198         uint32_t next = value / 10;
00199         buf[pos] = '0' + (value - next * 10);
00200         value = next;
00201         pos++;
00202     }
00203 
00204     // Reverse order
00205     for (uint32_t i = 0; i < pos / 2; i++) {
00206         char temp = buf[i];
00207         buf[i] = buf[pos - 1 - i];
00208         buf[pos - 1 - i] = temp;
00209     }
00210 
00211     return pos;
00212 }
00213 
00214 #endif