From 1dad73949caaa8f1d4275bb8e83463bd2ce8ed42 Mon Sep 17 00:00:00 2001 From: deepikabhavnani Date: Tue, 1 May 2018 13:43:10 -0500 Subject: [PATCH] Thread statistics addition. API to get all system threads information and states. --- TESTS/mbed_platform/stats_thread/main.cpp | 171 ++++++++++++++++++++++ platform/mbed_stats.c | 34 ++++- platform/mbed_stats.h | 24 +++ 3 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 TESTS/mbed_platform/stats_thread/main.cpp diff --git a/TESTS/mbed_platform/stats_thread/main.cpp b/TESTS/mbed_platform/stats_thread/main.cpp new file mode 100644 index 0000000000..66151a3d89 --- /dev/null +++ b/TESTS/mbed_platform/stats_thread/main.cpp @@ -0,0 +1,171 @@ +/* + * 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 "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest/utest.h" +#include "mbed_stats.h" +#include +#include + +#if !defined(MBED_THREAD_STATS_ENABLED) + #warning [NOT_SUPPORTED] test not supported +#endif + +using namespace utest::v1; + +static EventFlags ef; +static int32_t counter = 0; + +#define TEST_STACK_SIZE 320 +#define FLAG_SIGNAL_DEC 0x2 +#define MAX_THREAD_STATS 0x8 + +void decrement_on_event() +{ + uint32_t ret = ef.wait_all(FLAG_SIGNAL_DEC); + TEST_ASSERT_FALSE(ret & osFlagsError); + TEST_ASSERT_EQUAL(FLAG_SIGNAL_DEC, ret); + counter--; +} + +void increment_with_delay() +{ + while (1) { + counter++; + Thread::wait(500); + } +} + +void test_case_single_thread_stats() +{ + Thread t1(osPriorityNormal, TEST_STACK_SIZE, NULL, "Th1"); + t1.start(increment_with_delay); + + // Read stats + mbed_stats_thread_t *stats = new mbed_stats_thread_t[MAX_THREAD_STATS]; + int count = mbed_stats_thread_get_each(stats, MAX_THREAD_STATS); + TEST_ASSERT_EQUAL(4, count); + + for (int i = 0; i < count; i++) { + if (0 == strcmp (stats[i].thread_name, "Th1")) { + TEST_ASSERT_EQUAL(TEST_STACK_SIZE, stats[i].thread_stack_size); + TEST_ASSERT_EQUAL(osPriorityNormal, stats[i].thread_priority); + break; + } + } + delete[] stats; + t1.terminate(); +} + +void test_case_less_count() +{ + // Default Mbed OS has 3 threads + mbed_stats_thread_t *stats = new mbed_stats_thread_t[2]; + int count = mbed_stats_thread_get_each(stats, 2); + TEST_ASSERT_EQUAL(2, count); + delete[] stats; +} + +void test_case_multi_threads_blocked() +{ + Thread t1(osPriorityNormal, TEST_STACK_SIZE, NULL, "Th1"); + Thread t2(osPriorityNormal1, TEST_STACK_SIZE, NULL, "Th2"); + t1.start(increment_with_delay); + t2.start(decrement_on_event); + + // Read stats + mbed_stats_thread_t *stats = new mbed_stats_thread_t[MAX_THREAD_STATS]; + int count = mbed_stats_thread_get_each(stats, MAX_THREAD_STATS); + TEST_ASSERT_EQUAL(5, count); + + for (int i = 0; i < count; i++) { + if (0 == strcmp (stats[i].thread_name, "Th2")) { + TEST_ASSERT_EQUAL(TEST_STACK_SIZE, stats[i].thread_stack_size); + TEST_ASSERT_EQUAL(osPriorityNormal1, stats[i].thread_priority); + TEST_ASSERT_EQUAL(osThreadBlocked, stats[i].thread_state); + } else if (0 == strcmp (stats[i].thread_name, "Th1")) { + TEST_ASSERT_EQUAL(TEST_STACK_SIZE, stats[i].thread_stack_size); + TEST_ASSERT_EQUAL(osPriorityNormal, stats[i].thread_priority); + } + } + + // Signal blocked thread + uint32_t ret = ef.set(FLAG_SIGNAL_DEC); + TEST_ASSERT_FALSE(ret & osFlagsError); + + Thread::wait(100); + + count = mbed_stats_thread_get_each(stats, MAX_THREAD_STATS); + TEST_ASSERT_EQUAL(4, count); + + delete[] stats; + t1.terminate(); +} + +void test_case_multi_threads_terminate() +{ + Thread t1(osPriorityNormal1, TEST_STACK_SIZE, NULL, "Th1"); + Thread t2(osPriorityNormal2, TEST_STACK_SIZE, NULL, "Th2"); + t2.start(increment_with_delay); + t1.start(decrement_on_event); + + // Read stats + mbed_stats_thread_t *stats = new mbed_stats_thread_t[MAX_THREAD_STATS]; + int count = mbed_stats_thread_get_each(stats, MAX_THREAD_STATS); + TEST_ASSERT_EQUAL(5, count); + + for (int i = 0; i < count; i++) { + if (0 == strcmp (stats[i].thread_name, "Th2")) { + TEST_ASSERT_EQUAL(TEST_STACK_SIZE, stats[i].thread_stack_size); + TEST_ASSERT_EQUAL(osPriorityNormal2, stats[i].thread_priority); + } else if (0 == strcmp (stats[i].thread_name, "Th1")) { + TEST_ASSERT_EQUAL(TEST_STACK_SIZE, stats[i].thread_stack_size); + TEST_ASSERT_EQUAL(osPriorityNormal1, stats[i].thread_priority); + TEST_ASSERT_EQUAL(osThreadBlocked, stats[i].thread_state); + } + } + + t1.terminate(); + t2.terminate(); + + count = mbed_stats_thread_get_each(stats, MAX_THREAD_STATS); + TEST_ASSERT_EQUAL(3, count); + + delete[] stats; + t1.terminate(); +} + +Case cases[] = { + Case("Single Thread Stats", test_case_single_thread_stats), + Case("Less count value", test_case_less_count), + Case("Multiple Threads blocked", test_case_multi_threads_blocked), + Case("Multiple Threads terminate", test_case_multi_threads_terminate), +}; + +utest::v1::status_t greentea_test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(20, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler); + +int main() +{ + Harness::run(specification); +} diff --git a/platform/mbed_stats.c b/platform/mbed_stats.c index de54b13974..949d1b14ef 100644 --- a/platform/mbed_stats.c +++ b/platform/mbed_stats.c @@ -67,6 +67,36 @@ size_t mbed_stats_stack_get_each(mbed_stats_stack_t *stats, size_t count) return i; } -#if defined(MBED_STACK_STATS_ENABLED) && !defined(MBED_CONF_RTOS_PRESENT) -#warning Stack statistics are currently not supported without the rtos. +size_t mbed_stats_thread_get_each(mbed_stats_thread_t *stats, size_t count) +{ + MBED_ASSERT(stats != NULL); + memset(stats, 0, count*sizeof(mbed_stats_thread_t)); + size_t i = 0; + +#if defined(MBED_THREAD_STATS_ENABLED) && MBED_CONF_RTOS_PRESENT + osThreadId_t *threads; + + threads = malloc(sizeof(osThreadId_t) * count); + MBED_ASSERT(threads != NULL); + + osKernelLock(); + count = osThreadEnumerate(threads, count); + + for(i = 0; i < count; i++) { + stats[i].thread_id = (uint32_t)threads[i]; + stats[i].thread_state = (uint32_t)osThreadGetState(threads[i]); + stats[i].thread_priority = (uint32_t)osThreadGetPriority(threads[i]); + stats[i].thread_stack_size = osThreadGetStackSize(threads[i]); + stats[i].thread_stack_space = osThreadGetStackSpace(threads[i]); + stats[i].thread_name = osThreadGetName(threads[i]); + } + osKernelUnlock(); + free(threads); +#endif + + return i; +} + +#if (defined(MBED_STACK_STATS_ENABLED) || defined(MBED_THREAD_STATS_ENABLED)) && !defined(MBED_CONF_RTOS_PRESENT) +#warning statistics are currently not supported without the rtos. #endif diff --git a/platform/mbed_stats.h b/platform/mbed_stats.h index e86507991d..9b5262429e 100644 --- a/platform/mbed_stats.h +++ b/platform/mbed_stats.h @@ -32,6 +32,7 @@ extern "C" { #ifdef MBED_ALL_STATS_ENABLED #define MBED_STACK_STATS_ENABLED 1 #define MBED_HEAP_STATS_ENABLED 1 +#define MBED_THREAD_STATS_ENABLED 1 #endif /** @@ -46,6 +47,19 @@ typedef struct { uint32_t alloc_fail_cnt; /**< Number of failed allocations. */ } mbed_stats_heap_t; +/** + * struct mbed_stats_thread_t definition + */ + +typedef struct { + uint32_t thread_id; /**< Thread Object Identifier */ + uint32_t thread_state; /**< Thread Object State */ + uint32_t thread_priority; /**< Thread Priority */ + uint32_t thread_stack_size; /**< Thread Stack Size */ + uint32_t thread_stack_space; /**< Thread remaining stack size */ + const char *thread_name; /**< Thread Object name */ +} mbed_stats_thread_t; + /** * Fill the passed in heap stat structure with heap stats. * @@ -81,6 +95,16 @@ void mbed_stats_stack_get(mbed_stats_stack_t *stats); */ size_t mbed_stats_stack_get_each(mbed_stats_stack_t *stats, size_t count); +/** + * Fill the passed array of stat structures with the thread stats for each available thread. + * + * @param stats A pointer to an array of mbed_stats_thread_t structures to fill + * @param count The number of mbed_stats_thread_t structures in the provided array + * @return The number of mbed_stats_thread_t structures that have been filled, + * this is equal to the number of stacks on the system. + */ +size_t mbed_stats_thread_get_each(mbed_stats_thread_t *stats, size_t count); + #ifdef __cplusplus } #endif