takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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