Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

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