-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2642 from c1728p9/stack_stats
Stack stats
- Loading branch information
Showing
15 changed files
with
631 additions
and
17 deletions.
There are no files selected for viewing
14 changes: 14 additions & 0 deletions
14
features/frameworks/greentea-client/greentea-client/greentea_metrics.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#ifndef GREENTEA_METRICS_H | ||
#define GREENTEA_METRICS_H | ||
|
||
/** | ||
* Setup platform specific metrics | ||
*/ | ||
void greentea_metrics_setup(void); | ||
|
||
/** | ||
* Report and cleanup platform specifc metrics | ||
*/ | ||
void greentea_metrics_report(void); | ||
|
||
#endif |
207 changes: 207 additions & 0 deletions
207
features/frameworks/greentea-client/source/greentea_metrics.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/* | ||
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include "mbed.h" | ||
#include "rtos.h" | ||
#include "mbed_stats.h" | ||
#include "cmsis_os.h" | ||
#include "greentea-client/test_env.h" | ||
#include "greentea-client/greentea_metrics.h" | ||
#include "SingletonPtr.h" | ||
#include "CircularBuffer.h" | ||
|
||
#define THREAD_BUF_COUNT 16 | ||
|
||
typedef struct { | ||
uint32_t entry; | ||
uint32_t arg; | ||
uint32_t stack_size; | ||
uint32_t max_stack; | ||
} thread_info_t; | ||
|
||
// Mutex to protect "buf" | ||
SingletonPtr<Mutex> mutex; | ||
static char buf[128]; | ||
static SingletonPtr<CircularBuffer<thread_info_t, THREAD_BUF_COUNT> > queue; | ||
|
||
static void send_heap_info(void); | ||
static void send_stack_info(void); | ||
static void on_thread_terminate(osThreadId id); | ||
static void enqeue_thread_info(osThreadId id); | ||
static void deque_and_print_thread_info(void); | ||
|
||
// sprintf uses a lot of stack so use these instead | ||
static uint32_t print_hex(char *buf, uint32_t value); | ||
static uint32_t print_dec(char *buf, uint32_t value); | ||
|
||
void greentea_metrics_setup() | ||
{ | ||
#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED | ||
Thread::attach_terminate_hook(on_thread_terminate); | ||
#endif | ||
} | ||
|
||
void greentea_metrics_report() | ||
{ | ||
send_heap_info(); | ||
#if defined(MBED_STACK_STATS_ENABLED) && MBED_STACK_STATS_ENABLED | ||
send_stack_info(); | ||
Thread::attach_terminate_hook(NULL); | ||
#endif | ||
} | ||
|
||
static void send_heap_info() | ||
{ | ||
mbed_stats_heap_t heap_stats; | ||
mbed_stats_heap_get(&heap_stats); | ||
greentea_send_kv("max_heap_usage",heap_stats.max_size); | ||
} | ||
|
||
MBED_UNUSED static void send_stack_info() | ||
{ | ||
mutex->lock(); | ||
|
||
// Flush any queued stack entries | ||
while (!queue->empty()) { | ||
deque_and_print_thread_info(); | ||
} | ||
|
||
// Print info for all other threads | ||
osThreadEnumId enum_id = _osThreadsEnumStart(); | ||
while (true) { | ||
osThreadId thread_id = _osThreadEnumNext(enum_id); | ||
if (NULL == thread_id) { | ||
// End of enumeration | ||
break; | ||
} | ||
enqeue_thread_info(thread_id); | ||
deque_and_print_thread_info(); | ||
} | ||
_osThreadEnumFree(enum_id); | ||
|
||
mutex->unlock(); | ||
} | ||
|
||
MBED_UNUSED static void on_thread_terminate(osThreadId id) | ||
{ | ||
mutex->lock(); | ||
|
||
// There should always be space in the queue | ||
enqeue_thread_info(id); | ||
|
||
// If queue is full then print out a single entry | ||
if (queue->full()) { | ||
deque_and_print_thread_info(); | ||
} | ||
|
||
mutex->unlock(); | ||
} | ||
|
||
static void enqeue_thread_info(osThreadId id) | ||
{ | ||
osEvent info; | ||
thread_info_t thread_info = {}; | ||
info = _osThreadGetInfo(id, osThreadInfoEntry); | ||
if (info.status != osOK) { | ||
return; | ||
} | ||
thread_info.entry = (uint32_t)info.value.p; | ||
info = _osThreadGetInfo(id, osThreadInfoArg); | ||
if (info.status != osOK) { | ||
return; | ||
} | ||
thread_info.arg = (uint32_t)info.value.p; | ||
info = _osThreadGetInfo(id, osThreadInfoStackSize); | ||
if (info.status != osOK) { | ||
return; | ||
} | ||
thread_info.stack_size = (uint32_t)info.value.v; | ||
info = _osThreadGetInfo(id, osThreadInfoStackMax); | ||
if (info.status != osOK) { | ||
return; | ||
} | ||
thread_info.max_stack = (uint32_t)info.value.v; | ||
queue->push(thread_info); | ||
} | ||
|
||
static void deque_and_print_thread_info() | ||
{ | ||
thread_info_t thread_info; | ||
bool ret = queue->pop(thread_info); | ||
MBED_ASSERT(ret); | ||
uint32_t pos = 0; | ||
buf[pos++] = '\"'; | ||
pos += print_hex(buf + pos, thread_info.entry); | ||
buf[pos++] = '-'; | ||
pos += print_hex(buf + pos, thread_info.arg); | ||
buf[pos++] = '\"'; | ||
buf[pos++] = ','; | ||
pos += print_dec(buf + pos, thread_info.max_stack); | ||
buf[pos++] = ','; | ||
pos += print_dec(buf + pos, thread_info.stack_size); | ||
buf[pos++] = 0; | ||
greentea_send_kv("__thread_info", buf); | ||
} | ||
|
||
static uint32_t print_hex(char *buf, uint32_t value) | ||
{ | ||
uint32_t pos = 0; | ||
buf[pos] = '0'; | ||
pos++; | ||
buf[pos] = 'x'; | ||
pos++; | ||
for (int i = 8; i >= 0; i--) { | ||
uint32_t val = (value >> (4 * i)) & 0xF; | ||
if (val <= 9) { | ||
buf[pos] = '0' + val; | ||
pos++; | ||
} else { | ||
buf[pos] = 'a' + val - 10; | ||
pos++; | ||
} | ||
} | ||
return pos; | ||
} | ||
|
||
static uint32_t print_dec(char *buf, uint32_t value) | ||
{ | ||
uint32_t pos = 0; | ||
|
||
// The value 0 is special case | ||
if (0 == value) { | ||
buf[pos] = '0'; | ||
pos++; | ||
return pos; | ||
} | ||
|
||
// Write out value in reverse order | ||
while (value != 0) { | ||
uint32_t next = value / 10; | ||
buf[pos] = '0' + (value - next * 10); | ||
value = next; | ||
pos++; | ||
} | ||
|
||
// Reverse order | ||
for (uint32_t i = 0; i < pos / 2; i++) { | ||
char temp = buf[i]; | ||
buf[i] = buf[pos - 1 - i]; | ||
buf[pos - 1 - i] = temp; | ||
} | ||
|
||
return pos; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.