Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more
features/frameworks/greentea-client/source/greentea_metrics.cpp@0:f782d9c66c49, 2018-02-02 (annotated)
- Committer:
- dkato
- Date:
- Fri Feb 02 05:42:23 2018 +0000
- Revision:
- 0:f782d9c66c49
mbed-os for GR-LYCHEE
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dkato | 0:f782d9c66c49 | 1 | /* |
dkato | 0:f782d9c66c49 | 2 | * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved |
dkato | 0:f782d9c66c49 | 3 | * SPDX-License-Identifier: Apache-2.0 |
dkato | 0:f782d9c66c49 | 4 | * |
dkato | 0:f782d9c66c49 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
dkato | 0:f782d9c66c49 | 6 | * not use this file except in compliance with the License. |
dkato | 0:f782d9c66c49 | 7 | * You may obtain a copy of the License at |
dkato | 0:f782d9c66c49 | 8 | * |
dkato | 0:f782d9c66c49 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
dkato | 0:f782d9c66c49 | 10 | * |
dkato | 0:f782d9c66c49 | 11 | * Unless required by applicable law or agreed to in writing, software |
dkato | 0:f782d9c66c49 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
dkato | 0:f782d9c66c49 | 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
dkato | 0:f782d9c66c49 | 14 | * See the License for the specific language governing permissions and |
dkato | 0:f782d9c66c49 | 15 | * limitations under the License. |
dkato | 0:f782d9c66c49 | 16 | */ |
dkato | 0:f782d9c66c49 | 17 | |
dkato | 0:f782d9c66c49 | 18 | #include "mbed.h" |
dkato | 0:f782d9c66c49 | 19 | #include "rtos.h" |
dkato | 0:f782d9c66c49 | 20 | #include "mbed_stats.h" |
dkato | 0:f782d9c66c49 | 21 | #include "cmsis_os.h" |
dkato | 0:f782d9c66c49 | 22 | #include "greentea-client/test_env.h" |
dkato | 0:f782d9c66c49 | 23 | #include "greentea-client/greentea_metrics.h" |
dkato | 0:f782d9c66c49 | 24 | #include "SingletonPtr.h" |
dkato | 0:f782d9c66c49 | 25 | #include "CircularBuffer.h" |
dkato | 0:f782d9c66c49 | 26 | |
dkato | 0:f782d9c66c49 | 27 | #define THREAD_BUF_COUNT 16 |
dkato | 0:f782d9c66c49 | 28 | |
dkato | 0:f782d9c66c49 | 29 | typedef struct { |
dkato | 0:f782d9c66c49 | 30 | uint32_t entry; |
dkato | 0:f782d9c66c49 | 31 | uint32_t arg; |
dkato | 0:f782d9c66c49 | 32 | uint32_t stack_size; |
dkato | 0:f782d9c66c49 | 33 | uint32_t max_stack; |
dkato | 0:f782d9c66c49 | 34 | } thread_info_t; |
dkato | 0:f782d9c66c49 | 35 | |
dkato | 0:f782d9c66c49 | 36 | // Mutex to protect "buf" |
dkato | 0:f782d9c66c49 | 37 | static SingletonPtr<Mutex> mutex; |
dkato | 0:f782d9c66c49 | 38 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
dkato | 0:f782d9c66c49 | 39 | static char buf[128]; |
dkato | 0:f782d9c66c49 | 40 | static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue; |
dkato | 0:f782d9c66c49 | 41 | #endif |
dkato | 0:f782d9c66c49 | 42 | |
dkato | 0:f782d9c66c49 | 43 | static void send_heap_info(void); |
dkato | 0:f782d9c66c49 | 44 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
dkato | 0:f782d9c66c49 | 45 | static void send_stack_info(void); |
dkato | 0:f782d9c66c49 | 46 | static void on_thread_terminate(osThreadId id); |
dkato | 0:f782d9c66c49 | 47 | static void enqeue_thread_info(osThreadId id); |
dkato | 0:f782d9c66c49 | 48 | static void deque_and_print_thread_info(void); |
dkato | 0:f782d9c66c49 | 49 | |
dkato | 0:f782d9c66c49 | 50 | // sprintf uses a lot of stack so use these instead |
dkato | 0:f782d9c66c49 | 51 | static uint32_t print_hex(char *buf, uint32_t value); |
dkato | 0:f782d9c66c49 | 52 | static uint32_t print_dec(char *buf, uint32_t value); |
dkato | 0:f782d9c66c49 | 53 | #endif |
dkato | 0:f782d9c66c49 | 54 | |
dkato | 0:f782d9c66c49 | 55 | void greentea_metrics_setup() |
dkato | 0:f782d9c66c49 | 56 | { |
dkato | 0:f782d9c66c49 | 57 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
dkato | 0:f782d9c66c49 | 58 | Thread::attach_terminate_hook(on_thread_terminate); |
dkato | 0:f782d9c66c49 | 59 | #endif |
dkato | 0:f782d9c66c49 | 60 | } |
dkato | 0:f782d9c66c49 | 61 | |
dkato | 0:f782d9c66c49 | 62 | void greentea_metrics_report() |
dkato | 0:f782d9c66c49 | 63 | { |
dkato | 0:f782d9c66c49 | 64 | send_heap_info(); |
dkato | 0:f782d9c66c49 | 65 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
dkato | 0:f782d9c66c49 | 66 | send_stack_info(); |
dkato | 0:f782d9c66c49 | 67 | Thread::attach_terminate_hook(NULL); |
dkato | 0:f782d9c66c49 | 68 | #endif |
dkato | 0:f782d9c66c49 | 69 | } |
dkato | 0:f782d9c66c49 | 70 | |
dkato | 0:f782d9c66c49 | 71 | static void send_heap_info() |
dkato | 0:f782d9c66c49 | 72 | { |
dkato | 0:f782d9c66c49 | 73 | mbed_stats_heap_t heap_stats; |
dkato | 0:f782d9c66c49 | 74 | mbed_stats_heap_get(&heap_stats); |
dkato | 0:f782d9c66c49 | 75 | greentea_send_kv("max_heap_usage",heap_stats.max_size); |
dkato | 0:f782d9c66c49 | 76 | } |
dkato | 0:f782d9c66c49 | 77 | |
dkato | 0:f782d9c66c49 | 78 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
dkato | 0:f782d9c66c49 | 79 | MBED_UNUSED static void send_stack_info() |
dkato | 0:f782d9c66c49 | 80 | { |
dkato | 0:f782d9c66c49 | 81 | mutex->lock(); |
dkato | 0:f782d9c66c49 | 82 | |
dkato | 0:f782d9c66c49 | 83 | // Flush any queued stack entries |
dkato | 0:f782d9c66c49 | 84 | while (!queue->empty()) { |
dkato | 0:f782d9c66c49 | 85 | deque_and_print_thread_info(); |
dkato | 0:f782d9c66c49 | 86 | } |
dkato | 0:f782d9c66c49 | 87 | |
dkato | 0:f782d9c66c49 | 88 | // Print info for all other threads |
dkato | 0:f782d9c66c49 | 89 | osThreadEnumId enum_id = _osThreadsEnumStart(); |
dkato | 0:f782d9c66c49 | 90 | while (true) { |
dkato | 0:f782d9c66c49 | 91 | osThreadId thread_id = _osThreadEnumNext(enum_id); |
dkato | 0:f782d9c66c49 | 92 | if (NULL == thread_id) { |
dkato | 0:f782d9c66c49 | 93 | // End of enumeration |
dkato | 0:f782d9c66c49 | 94 | break; |
dkato | 0:f782d9c66c49 | 95 | } |
dkato | 0:f782d9c66c49 | 96 | enqeue_thread_info(thread_id); |
dkato | 0:f782d9c66c49 | 97 | deque_and_print_thread_info(); |
dkato | 0:f782d9c66c49 | 98 | } |
dkato | 0:f782d9c66c49 | 99 | _osThreadEnumFree(enum_id); |
dkato | 0:f782d9c66c49 | 100 | |
dkato | 0:f782d9c66c49 | 101 | mutex->unlock(); |
dkato | 0:f782d9c66c49 | 102 | } |
dkato | 0:f782d9c66c49 | 103 | |
dkato | 0:f782d9c66c49 | 104 | MBED_UNUSED static void on_thread_terminate(osThreadId id) |
dkato | 0:f782d9c66c49 | 105 | { |
dkato | 0:f782d9c66c49 | 106 | mutex->lock(); |
dkato | 0:f782d9c66c49 | 107 | |
dkato | 0:f782d9c66c49 | 108 | // There should always be space in the queue |
dkato | 0:f782d9c66c49 | 109 | enqeue_thread_info(id); |
dkato | 0:f782d9c66c49 | 110 | |
dkato | 0:f782d9c66c49 | 111 | // If queue is full then print out a single entry |
dkato | 0:f782d9c66c49 | 112 | if (queue->full()) { |
dkato | 0:f782d9c66c49 | 113 | deque_and_print_thread_info(); |
dkato | 0:f782d9c66c49 | 114 | } |
dkato | 0:f782d9c66c49 | 115 | |
dkato | 0:f782d9c66c49 | 116 | mutex->unlock(); |
dkato | 0:f782d9c66c49 | 117 | } |
dkato | 0:f782d9c66c49 | 118 | |
dkato | 0:f782d9c66c49 | 119 | static void enqeue_thread_info(osThreadId id) |
dkato | 0:f782d9c66c49 | 120 | { |
dkato | 0:f782d9c66c49 | 121 | osEvent info; |
dkato | 0:f782d9c66c49 | 122 | thread_info_t thread_info = {}; |
dkato | 0:f782d9c66c49 | 123 | info = _osThreadGetInfo(id, osThreadInfoEntry); |
dkato | 0:f782d9c66c49 | 124 | if (info.status != osOK) { |
dkato | 0:f782d9c66c49 | 125 | return; |
dkato | 0:f782d9c66c49 | 126 | } |
dkato | 0:f782d9c66c49 | 127 | thread_info.entry = (uint32_t)info.value.p; |
dkato | 0:f782d9c66c49 | 128 | info = _osThreadGetInfo(id, osThreadInfoArg); |
dkato | 0:f782d9c66c49 | 129 | if (info.status != osOK) { |
dkato | 0:f782d9c66c49 | 130 | return; |
dkato | 0:f782d9c66c49 | 131 | } |
dkato | 0:f782d9c66c49 | 132 | thread_info.arg = (uint32_t)info.value.p; |
dkato | 0:f782d9c66c49 | 133 | info = _osThreadGetInfo(id, osThreadInfoStackSize); |
dkato | 0:f782d9c66c49 | 134 | if (info.status != osOK) { |
dkato | 0:f782d9c66c49 | 135 | return; |
dkato | 0:f782d9c66c49 | 136 | } |
dkato | 0:f782d9c66c49 | 137 | thread_info.stack_size = (uint32_t)info.value.v; |
dkato | 0:f782d9c66c49 | 138 | info = _osThreadGetInfo(id, osThreadInfoStackMax); |
dkato | 0:f782d9c66c49 | 139 | if (info.status != osOK) { |
dkato | 0:f782d9c66c49 | 140 | return; |
dkato | 0:f782d9c66c49 | 141 | } |
dkato | 0:f782d9c66c49 | 142 | thread_info.max_stack = (uint32_t)info.value.v; |
dkato | 0:f782d9c66c49 | 143 | queue->push(thread_info); |
dkato | 0:f782d9c66c49 | 144 | } |
dkato | 0:f782d9c66c49 | 145 | |
dkato | 0:f782d9c66c49 | 146 | static void deque_and_print_thread_info() |
dkato | 0:f782d9c66c49 | 147 | { |
dkato | 0:f782d9c66c49 | 148 | thread_info_t thread_info; |
dkato | 0:f782d9c66c49 | 149 | bool ret = queue->pop(thread_info); |
dkato | 0:f782d9c66c49 | 150 | MBED_ASSERT(ret); |
dkato | 0:f782d9c66c49 | 151 | uint32_t pos = 0; |
dkato | 0:f782d9c66c49 | 152 | buf[pos++] = '\"'; |
dkato | 0:f782d9c66c49 | 153 | pos += print_hex(buf + pos, thread_info.entry); |
dkato | 0:f782d9c66c49 | 154 | buf[pos++] = '-'; |
dkato | 0:f782d9c66c49 | 155 | pos += print_hex(buf + pos, thread_info.arg); |
dkato | 0:f782d9c66c49 | 156 | buf[pos++] = '\"'; |
dkato | 0:f782d9c66c49 | 157 | buf[pos++] = ','; |
dkato | 0:f782d9c66c49 | 158 | pos += print_dec(buf + pos, thread_info.max_stack); |
dkato | 0:f782d9c66c49 | 159 | buf[pos++] = ','; |
dkato | 0:f782d9c66c49 | 160 | pos += print_dec(buf + pos, thread_info.stack_size); |
dkato | 0:f782d9c66c49 | 161 | buf[pos++] = 0; |
dkato | 0:f782d9c66c49 | 162 | greentea_send_kv("__thread_info", buf); |
dkato | 0:f782d9c66c49 | 163 | } |
dkato | 0:f782d9c66c49 | 164 | |
dkato | 0:f782d9c66c49 | 165 | static uint32_t print_hex(char *buf, uint32_t value) |
dkato | 0:f782d9c66c49 | 166 | { |
dkato | 0:f782d9c66c49 | 167 | uint32_t pos = 0; |
dkato | 0:f782d9c66c49 | 168 | buf[pos] = '0'; |
dkato | 0:f782d9c66c49 | 169 | pos++; |
dkato | 0:f782d9c66c49 | 170 | buf[pos] = 'x'; |
dkato | 0:f782d9c66c49 | 171 | pos++; |
dkato | 0:f782d9c66c49 | 172 | for (int i = 8; i >= 0; i--) { |
dkato | 0:f782d9c66c49 | 173 | uint32_t val = (value >> (4 * i)) & 0xF; |
dkato | 0:f782d9c66c49 | 174 | if (val <= 9) { |
dkato | 0:f782d9c66c49 | 175 | buf[pos] = '0' + val; |
dkato | 0:f782d9c66c49 | 176 | pos++; |
dkato | 0:f782d9c66c49 | 177 | } else { |
dkato | 0:f782d9c66c49 | 178 | buf[pos] = 'a' + val - 10; |
dkato | 0:f782d9c66c49 | 179 | pos++; |
dkato | 0:f782d9c66c49 | 180 | } |
dkato | 0:f782d9c66c49 | 181 | } |
dkato | 0:f782d9c66c49 | 182 | return pos; |
dkato | 0:f782d9c66c49 | 183 | } |
dkato | 0:f782d9c66c49 | 184 | |
dkato | 0:f782d9c66c49 | 185 | static uint32_t print_dec(char *buf, uint32_t value) |
dkato | 0:f782d9c66c49 | 186 | { |
dkato | 0:f782d9c66c49 | 187 | uint32_t pos = 0; |
dkato | 0:f782d9c66c49 | 188 | |
dkato | 0:f782d9c66c49 | 189 | // The value 0 is special case |
dkato | 0:f782d9c66c49 | 190 | if (0 == value) { |
dkato | 0:f782d9c66c49 | 191 | buf[pos] = '0'; |
dkato | 0:f782d9c66c49 | 192 | pos++; |
dkato | 0:f782d9c66c49 | 193 | return pos; |
dkato | 0:f782d9c66c49 | 194 | } |
dkato | 0:f782d9c66c49 | 195 | |
dkato | 0:f782d9c66c49 | 196 | // Write out value in reverse order |
dkato | 0:f782d9c66c49 | 197 | while (value != 0) { |
dkato | 0:f782d9c66c49 | 198 | uint32_t next = value / 10; |
dkato | 0:f782d9c66c49 | 199 | buf[pos] = '0' + (value - next * 10); |
dkato | 0:f782d9c66c49 | 200 | value = next; |
dkato | 0:f782d9c66c49 | 201 | pos++; |
dkato | 0:f782d9c66c49 | 202 | } |
dkato | 0:f782d9c66c49 | 203 | |
dkato | 0:f782d9c66c49 | 204 | // Reverse order |
dkato | 0:f782d9c66c49 | 205 | for (uint32_t i = 0; i < pos / 2; i++) { |
dkato | 0:f782d9c66c49 | 206 | char temp = buf[i]; |
dkato | 0:f782d9c66c49 | 207 | buf[i] = buf[pos - 1 - i]; |
dkato | 0:f782d9c66c49 | 208 | buf[pos - 1 - i] = temp; |
dkato | 0:f782d9c66c49 | 209 | } |
dkato | 0:f782d9c66c49 | 210 | |
dkato | 0:f782d9c66c49 | 211 | return pos; |
dkato | 0:f782d9c66c49 | 212 | } |
dkato | 0:f782d9c66c49 | 213 | |
dkato | 0:f782d9c66c49 | 214 | #endif |