Skip to content

Commit

Permalink
Merge pull request #2642 from c1728p9/stack_stats
Browse files Browse the repository at this point in the history
Stack stats
  • Loading branch information
sg- authored Sep 16, 2016
2 parents 27eb9c0 + 8447843 commit 52fd7b6
Show file tree
Hide file tree
Showing 15 changed files with 631 additions and 17 deletions.
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 features/frameworks/greentea-client/source/greentea_metrics.cpp
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;
}
3 changes: 3 additions & 0 deletions features/frameworks/greentea-client/source/test_env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "greentea-client/greentea_serial.h"
#include "greentea-client/greentea_metrics.h"


/**
Expand Down Expand Up @@ -65,6 +66,7 @@ static void greentea_notify_version();
* This function is blocking.
*/
void GREENTEA_SETUP(const int timeout, const char *host_test_name) {
greentea_metrics_setup();
// Key-value protocol handshake function. Waits for {{__sync;...}} message
// Sync preamble: "{{__sync;0dad4a9d-59a3-4aec-810d-d5fb09d852c1}}"
// Example value of sync_uuid == "0dad4a9d-59a3-4aec-810d-d5fb09d852c1"
Expand Down Expand Up @@ -451,6 +453,7 @@ static void greentea_notify_completion(const int result) {
__gcov_flush();
coverage_report = false;
#endif
greentea_metrics_report();
greentea_send_kv(GREENTEA_TEST_ENV_END, val);
greentea_send_kv(GREENTEA_TEST_ENV_EXIT, 0);
}
Expand Down
4 changes: 0 additions & 4 deletions features/frameworks/utest/source/utest_greentea_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "greentea-client/test_env.h"
#include "utest/utest_stack_trace.h"
#include "utest/utest_serial.h"
#include "mbed_stats.h"

using namespace utest::v1;

Expand Down Expand Up @@ -106,10 +105,7 @@ utest::v1::status_t utest::v1::greentea_test_setup_handler(const size_t number_o
void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure)
{
UTEST_LOG_FUNCTION();
mbed_stats_heap_t heap_stats;
verbose_test_teardown_handler(passed, failed, failure);
mbed_stats_heap_get(&heap_stats);
greentea_send_kv("max_heap_usage",heap_stats.max_size);
greentea_send_kv(TEST_ENV_TESTCASE_SUMMARY, passed, failed);
int result = !(failed || (failure.reason && !(failure.reason & REASON_IGNORE)));
GREENTEA_TESTSUITE_RESULT(result);
Expand Down
25 changes: 20 additions & 5 deletions rtos/rtos/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@

extern "C" P_TCB rt_tid2ptcb(osThreadId thread_id);


static void (*terminate_hook)(osThreadId id) = 0;
extern "C" void thread_terminate_hook(osThreadId id)
{
if (terminate_hook != (void (*)(osThreadId))NULL) {
terminate_hook(id);
}
}

namespace rtos {

void Thread::constructor(osPriority priority,
Expand Down Expand Up @@ -74,10 +83,7 @@ osStatus Thread::start(Callback<void()> task) {
_thread_def.pthread = Thread::_thunk;
if (_thread_def.stack_pointer == NULL) {
_thread_def.stack_pointer = new uint32_t[_thread_def.stacksize/sizeof(uint32_t)];
if (_thread_def.stack_pointer == NULL) {
_mutex.unlock();
return osErrorNoMemory;
}
MBED_ASSERT(_thread_def.stack_pointer != NULL);
}

//Fill the stack with a magic word for maximum usage checking
Expand All @@ -88,8 +94,12 @@ osStatus Thread::start(Callback<void()> task) {
_task = task;
_tid = osThreadCreate(&_thread_def, this);
if (_tid == NULL) {
if (_dynamic_stack) delete[] (_thread_def.stack_pointer);
if (_dynamic_stack) {
delete[] (_thread_def.stack_pointer);
_thread_def.stack_pointer = (uint32_t*)NULL;
}
_mutex.unlock();
_join_sem.release();
return osErrorResource;
}

Expand Down Expand Up @@ -336,12 +346,17 @@ void Thread::attach_idle_hook(void (*fptr)(void)) {
rtos_attach_idle_hook(fptr);
}

void Thread::attach_terminate_hook(void (*fptr)(osThreadId id)) {
terminate_hook = fptr;
}

Thread::~Thread() {
// terminate is thread safe
terminate();
#ifdef __MBED_CMSIS_RTOS_CM
if (_dynamic_stack) {
delete[] (_thread_def.stack_pointer);
_thread_def.stack_pointer = (uint32_t*)NULL;
}
#endif
}
Expand Down
5 changes: 5 additions & 0 deletions rtos/rtos/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ class Thread {
*/
static void attach_idle_hook(void (*fptr)(void));

/** Attach a function to be called when a task is killed
@param fptr pointer to the function to be called
*/
static void attach_terminate_hook(void (*fptr)(osThreadId id));

virtual ~Thread();

private:
Expand Down
8 changes: 8 additions & 0 deletions rtos/rtx/TARGET_CORTEX_A/RTX_Conf_CA.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,14 @@ void os_error (uint32_t err_code) {
for (;;);
}

/*----------------------------------------------------------------------------
* RTX Hooks
*---------------------------------------------------------------------------*/
extern void thread_terminate_hook(osThreadId id);

void sysThreadTerminate(osThreadId id) {
thread_terminate_hook(id);
}

/*----------------------------------------------------------------------------
* RTX Configuration Functions
Expand Down
Loading

0 comments on commit 52fd7b6

Please sign in to comment.