mbed-os
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
features/frameworks/greentea-client/source/greentea_metrics.cpp@0:b74591d5ab33, 2017-12-11 (annotated)
- Committer:
- be_bryan
- Date:
- Mon Dec 11 17:54:04 2017 +0000
- Revision:
- 0:b74591d5ab33
motor ++
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
be_bryan | 0:b74591d5ab33 | 1 | /* |
be_bryan | 0:b74591d5ab33 | 2 | * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved |
be_bryan | 0:b74591d5ab33 | 3 | * SPDX-License-Identifier: Apache-2.0 |
be_bryan | 0:b74591d5ab33 | 4 | * |
be_bryan | 0:b74591d5ab33 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
be_bryan | 0:b74591d5ab33 | 6 | * not use this file except in compliance with the License. |
be_bryan | 0:b74591d5ab33 | 7 | * You may obtain a copy of the License at |
be_bryan | 0:b74591d5ab33 | 8 | * |
be_bryan | 0:b74591d5ab33 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
be_bryan | 0:b74591d5ab33 | 10 | * |
be_bryan | 0:b74591d5ab33 | 11 | * Unless required by applicable law or agreed to in writing, software |
be_bryan | 0:b74591d5ab33 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
be_bryan | 0:b74591d5ab33 | 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
be_bryan | 0:b74591d5ab33 | 14 | * See the License for the specific language governing permissions and |
be_bryan | 0:b74591d5ab33 | 15 | * limitations under the License. |
be_bryan | 0:b74591d5ab33 | 16 | */ |
be_bryan | 0:b74591d5ab33 | 17 | |
be_bryan | 0:b74591d5ab33 | 18 | #include "mbed.h" |
be_bryan | 0:b74591d5ab33 | 19 | #include "rtos.h" |
be_bryan | 0:b74591d5ab33 | 20 | #include "mbed_stats.h" |
be_bryan | 0:b74591d5ab33 | 21 | #include "cmsis_os2.h" |
be_bryan | 0:b74591d5ab33 | 22 | #include "greentea-client/test_env.h" |
be_bryan | 0:b74591d5ab33 | 23 | #include "greentea-client/greentea_metrics.h" |
be_bryan | 0:b74591d5ab33 | 24 | #include "SingletonPtr.h" |
be_bryan | 0:b74591d5ab33 | 25 | #include "CircularBuffer.h" |
be_bryan | 0:b74591d5ab33 | 26 | |
be_bryan | 0:b74591d5ab33 | 27 | #define THREAD_BUF_COUNT 16 |
be_bryan | 0:b74591d5ab33 | 28 | |
be_bryan | 0:b74591d5ab33 | 29 | typedef struct { |
be_bryan | 0:b74591d5ab33 | 30 | uint32_t entry; |
be_bryan | 0:b74591d5ab33 | 31 | uint32_t stack_size; |
be_bryan | 0:b74591d5ab33 | 32 | uint32_t max_stack; |
be_bryan | 0:b74591d5ab33 | 33 | } thread_info_t; |
be_bryan | 0:b74591d5ab33 | 34 | |
be_bryan | 0:b74591d5ab33 | 35 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
be_bryan | 0:b74591d5ab33 | 36 | // Mutex to protect "buf" |
be_bryan | 0:b74591d5ab33 | 37 | static SingletonPtr<Mutex> mutex; |
be_bryan | 0:b74591d5ab33 | 38 | static char buf[128]; |
be_bryan | 0:b74591d5ab33 | 39 | static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue; |
be_bryan | 0:b74591d5ab33 | 40 | #endif |
be_bryan | 0:b74591d5ab33 | 41 | |
be_bryan | 0:b74591d5ab33 | 42 | static void send_heap_info(void); |
be_bryan | 0:b74591d5ab33 | 43 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
be_bryan | 0:b74591d5ab33 | 44 | static void send_stack_info(void); |
be_bryan | 0:b74591d5ab33 | 45 | static void on_thread_terminate(osThreadId_t id); |
be_bryan | 0:b74591d5ab33 | 46 | static void enqeue_thread_info(osThreadId_t id); |
be_bryan | 0:b74591d5ab33 | 47 | static void deque_and_print_thread_info(void); |
be_bryan | 0:b74591d5ab33 | 48 | |
be_bryan | 0:b74591d5ab33 | 49 | // sprintf uses a lot of stack so use these instead |
be_bryan | 0:b74591d5ab33 | 50 | static uint32_t print_hex(char *buf, uint32_t value); |
be_bryan | 0:b74591d5ab33 | 51 | static uint32_t print_dec(char *buf, uint32_t value); |
be_bryan | 0:b74591d5ab33 | 52 | #endif |
be_bryan | 0:b74591d5ab33 | 53 | |
be_bryan | 0:b74591d5ab33 | 54 | void greentea_metrics_setup() |
be_bryan | 0:b74591d5ab33 | 55 | { |
be_bryan | 0:b74591d5ab33 | 56 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
be_bryan | 0:b74591d5ab33 | 57 | Thread::attach_terminate_hook(on_thread_terminate); |
be_bryan | 0:b74591d5ab33 | 58 | #endif |
be_bryan | 0:b74591d5ab33 | 59 | } |
be_bryan | 0:b74591d5ab33 | 60 | |
be_bryan | 0:b74591d5ab33 | 61 | void greentea_metrics_report() |
be_bryan | 0:b74591d5ab33 | 62 | { |
be_bryan | 0:b74591d5ab33 | 63 | send_heap_info(); |
be_bryan | 0:b74591d5ab33 | 64 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
be_bryan | 0:b74591d5ab33 | 65 | send_stack_info(); |
be_bryan | 0:b74591d5ab33 | 66 | Thread::attach_terminate_hook(NULL); |
be_bryan | 0:b74591d5ab33 | 67 | #endif |
be_bryan | 0:b74591d5ab33 | 68 | } |
be_bryan | 0:b74591d5ab33 | 69 | |
be_bryan | 0:b74591d5ab33 | 70 | static void send_heap_info() |
be_bryan | 0:b74591d5ab33 | 71 | { |
be_bryan | 0:b74591d5ab33 | 72 | mbed_stats_heap_t heap_stats; |
be_bryan | 0:b74591d5ab33 | 73 | mbed_stats_heap_get(&heap_stats); |
be_bryan | 0:b74591d5ab33 | 74 | greentea_send_kv("max_heap_usage",heap_stats.max_size); |
be_bryan | 0:b74591d5ab33 | 75 | greentea_send_kv("reserved_heap",heap_stats.reserved_size); |
be_bryan | 0:b74591d5ab33 | 76 | } |
be_bryan | 0:b74591d5ab33 | 77 | |
be_bryan | 0:b74591d5ab33 | 78 | #if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED |
be_bryan | 0:b74591d5ab33 | 79 | MBED_UNUSED static void send_stack_info() |
be_bryan | 0:b74591d5ab33 | 80 | { |
be_bryan | 0:b74591d5ab33 | 81 | mutex->lock(); |
be_bryan | 0:b74591d5ab33 | 82 | |
be_bryan | 0:b74591d5ab33 | 83 | // Flush any queued stack entries |
be_bryan | 0:b74591d5ab33 | 84 | while (!queue->empty()) { |
be_bryan | 0:b74591d5ab33 | 85 | deque_and_print_thread_info(); |
be_bryan | 0:b74591d5ab33 | 86 | } |
be_bryan | 0:b74591d5ab33 | 87 | |
be_bryan | 0:b74591d5ab33 | 88 | // Print info for all other threads |
be_bryan | 0:b74591d5ab33 | 89 | uint32_t thread_n = osThreadGetCount(); |
be_bryan | 0:b74591d5ab33 | 90 | osThreadId_t *threads = new osThreadId_t[thread_n]; |
be_bryan | 0:b74591d5ab33 | 91 | thread_n = osThreadEnumerate(threads, thread_n); |
be_bryan | 0:b74591d5ab33 | 92 | |
be_bryan | 0:b74591d5ab33 | 93 | for(size_t i = 0; i < thread_n; i++) { |
be_bryan | 0:b74591d5ab33 | 94 | enqeue_thread_info(threads[i]); |
be_bryan | 0:b74591d5ab33 | 95 | deque_and_print_thread_info(); |
be_bryan | 0:b74591d5ab33 | 96 | } |
be_bryan | 0:b74591d5ab33 | 97 | |
be_bryan | 0:b74591d5ab33 | 98 | delete[] threads; |
be_bryan | 0:b74591d5ab33 | 99 | |
be_bryan | 0:b74591d5ab33 | 100 | mutex->unlock(); |
be_bryan | 0:b74591d5ab33 | 101 | } |
be_bryan | 0:b74591d5ab33 | 102 | |
be_bryan | 0:b74591d5ab33 | 103 | MBED_UNUSED static void on_thread_terminate(osThreadId_t id) |
be_bryan | 0:b74591d5ab33 | 104 | { |
be_bryan | 0:b74591d5ab33 | 105 | mutex->lock(); |
be_bryan | 0:b74591d5ab33 | 106 | |
be_bryan | 0:b74591d5ab33 | 107 | // There should always be space in the queue |
be_bryan | 0:b74591d5ab33 | 108 | enqeue_thread_info(id); |
be_bryan | 0:b74591d5ab33 | 109 | |
be_bryan | 0:b74591d5ab33 | 110 | // If queue is full then print out a single entry |
be_bryan | 0:b74591d5ab33 | 111 | if (queue->full()) { |
be_bryan | 0:b74591d5ab33 | 112 | deque_and_print_thread_info(); |
be_bryan | 0:b74591d5ab33 | 113 | } |
be_bryan | 0:b74591d5ab33 | 114 | |
be_bryan | 0:b74591d5ab33 | 115 | mutex->unlock(); |
be_bryan | 0:b74591d5ab33 | 116 | } |
be_bryan | 0:b74591d5ab33 | 117 | |
be_bryan | 0:b74591d5ab33 | 118 | static void enqeue_thread_info(osThreadId_t id) |
be_bryan | 0:b74591d5ab33 | 119 | { |
be_bryan | 0:b74591d5ab33 | 120 | thread_info_t thread_info = {}; |
be_bryan | 0:b74591d5ab33 | 121 | |
be_bryan | 0:b74591d5ab33 | 122 | thread_info.entry = (uint32_t)id; |
be_bryan | 0:b74591d5ab33 | 123 | thread_info.stack_size = osThreadGetStackSize(id); |
be_bryan | 0:b74591d5ab33 | 124 | thread_info.max_stack = thread_info.stack_size - osThreadGetStackSpace(id); |
be_bryan | 0:b74591d5ab33 | 125 | queue->push(thread_info); |
be_bryan | 0:b74591d5ab33 | 126 | } |
be_bryan | 0:b74591d5ab33 | 127 | |
be_bryan | 0:b74591d5ab33 | 128 | static void deque_and_print_thread_info() |
be_bryan | 0:b74591d5ab33 | 129 | { |
be_bryan | 0:b74591d5ab33 | 130 | thread_info_t thread_info; |
be_bryan | 0:b74591d5ab33 | 131 | bool ret = queue->pop(thread_info); |
be_bryan | 0:b74591d5ab33 | 132 | MBED_ASSERT(ret); |
be_bryan | 0:b74591d5ab33 | 133 | uint32_t pos = 0; |
be_bryan | 0:b74591d5ab33 | 134 | buf[pos++] = '\"'; |
be_bryan | 0:b74591d5ab33 | 135 | pos += print_hex(buf + pos, thread_info.entry); |
be_bryan | 0:b74591d5ab33 | 136 | buf[pos++] = '\"'; |
be_bryan | 0:b74591d5ab33 | 137 | buf[pos++] = ','; |
be_bryan | 0:b74591d5ab33 | 138 | pos += print_dec(buf + pos, thread_info.max_stack); |
be_bryan | 0:b74591d5ab33 | 139 | buf[pos++] = ','; |
be_bryan | 0:b74591d5ab33 | 140 | pos += print_dec(buf + pos, thread_info.stack_size); |
be_bryan | 0:b74591d5ab33 | 141 | buf[pos++] = 0; |
be_bryan | 0:b74591d5ab33 | 142 | greentea_send_kv("__thread_info", buf); |
be_bryan | 0:b74591d5ab33 | 143 | } |
be_bryan | 0:b74591d5ab33 | 144 | |
be_bryan | 0:b74591d5ab33 | 145 | static uint32_t print_hex(char *buf, uint32_t value) |
be_bryan | 0:b74591d5ab33 | 146 | { |
be_bryan | 0:b74591d5ab33 | 147 | uint32_t pos = 0; |
be_bryan | 0:b74591d5ab33 | 148 | buf[pos] = '0'; |
be_bryan | 0:b74591d5ab33 | 149 | pos++; |
be_bryan | 0:b74591d5ab33 | 150 | buf[pos] = 'x'; |
be_bryan | 0:b74591d5ab33 | 151 | pos++; |
be_bryan | 0:b74591d5ab33 | 152 | for (int i = 8; i >= 0; i--) { |
be_bryan | 0:b74591d5ab33 | 153 | uint32_t val = (value >> (4 * i)) & 0xF; |
be_bryan | 0:b74591d5ab33 | 154 | if (val <= 9) { |
be_bryan | 0:b74591d5ab33 | 155 | buf[pos] = '0' + val; |
be_bryan | 0:b74591d5ab33 | 156 | pos++; |
be_bryan | 0:b74591d5ab33 | 157 | } else { |
be_bryan | 0:b74591d5ab33 | 158 | buf[pos] = 'a' + val - 10; |
be_bryan | 0:b74591d5ab33 | 159 | pos++; |
be_bryan | 0:b74591d5ab33 | 160 | } |
be_bryan | 0:b74591d5ab33 | 161 | } |
be_bryan | 0:b74591d5ab33 | 162 | return pos; |
be_bryan | 0:b74591d5ab33 | 163 | } |
be_bryan | 0:b74591d5ab33 | 164 | |
be_bryan | 0:b74591d5ab33 | 165 | static uint32_t print_dec(char *buf, uint32_t value) |
be_bryan | 0:b74591d5ab33 | 166 | { |
be_bryan | 0:b74591d5ab33 | 167 | uint32_t pos = 0; |
be_bryan | 0:b74591d5ab33 | 168 | |
be_bryan | 0:b74591d5ab33 | 169 | // The value 0 is special case |
be_bryan | 0:b74591d5ab33 | 170 | if (0 == value) { |
be_bryan | 0:b74591d5ab33 | 171 | buf[pos] = '0'; |
be_bryan | 0:b74591d5ab33 | 172 | pos++; |
be_bryan | 0:b74591d5ab33 | 173 | return pos; |
be_bryan | 0:b74591d5ab33 | 174 | } |
be_bryan | 0:b74591d5ab33 | 175 | |
be_bryan | 0:b74591d5ab33 | 176 | // Write out value in reverse order |
be_bryan | 0:b74591d5ab33 | 177 | while (value != 0) { |
be_bryan | 0:b74591d5ab33 | 178 | uint32_t next = value / 10; |
be_bryan | 0:b74591d5ab33 | 179 | buf[pos] = '0' + (value - next * 10); |
be_bryan | 0:b74591d5ab33 | 180 | value = next; |
be_bryan | 0:b74591d5ab33 | 181 | pos++; |
be_bryan | 0:b74591d5ab33 | 182 | } |
be_bryan | 0:b74591d5ab33 | 183 | |
be_bryan | 0:b74591d5ab33 | 184 | // Reverse order |
be_bryan | 0:b74591d5ab33 | 185 | for (uint32_t i = 0; i < pos / 2; i++) { |
be_bryan | 0:b74591d5ab33 | 186 | char temp = buf[i]; |
be_bryan | 0:b74591d5ab33 | 187 | buf[i] = buf[pos - 1 - i]; |
be_bryan | 0:b74591d5ab33 | 188 | buf[pos - 1 - i] = temp; |
be_bryan | 0:b74591d5ab33 | 189 | } |
be_bryan | 0:b74591d5ab33 | 190 | |
be_bryan | 0:b74591d5ab33 | 191 | return pos; |
be_bryan | 0:b74591d5ab33 | 192 | } |
be_bryan | 0:b74591d5ab33 | 193 | |
be_bryan | 0:b74591d5ab33 | 194 | #endif |