Skip to content

CPU Statistics #6857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions TESTS/mbed_platform/stats_cpu/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@

/* mbed Microcontroller Library
* Copyright (c) 2018 ARM Limited
*
* 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 "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"

#include "mbed.h"

#if !defined(MBED_CPU_STATS_ENABLED) || !defined(DEVICE_LOWPOWERTIMER) || !defined(DEVICE_SLEEP)
#error [NOT_SUPPORTED] test not supported
#endif

using namespace utest::v1;

DigitalOut led1(LED1);

#define MAX_THREAD_STACK 384
#define SAMPLE_TIME 1000 // msec
#define LOOP_TIME 2000 // msec

static int32_t wait_time = 5000;

static void busy_thread()
{
volatile uint64_t i = ~0;

while (i--) {
led1 = !led1;
wait_us(wait_time);
}
}

void get_cpu_usage()
{
static uint64_t prev_idle_time = 0;
mbed_stats_cpu_t stats;

while (1) {
mbed_stats_cpu_get(&stats);
uint64_t diff = (stats.idle_time - prev_idle_time);
uint8_t usage = 100 - ((diff * 100) / (SAMPLE_TIME * 1000));
prev_idle_time = stats.idle_time;
TEST_ASSERT_NOT_EQUAL(0, usage);
Thread::wait(SAMPLE_TIME);
}
}

void test_cpu_info(void)
{
mbed_stats_cpu_t stats;
// Additional read to make sure timer is initialized
mbed_stats_cpu_get(&stats);
Thread::wait(1);
mbed_stats_cpu_get(&stats);
TEST_ASSERT_NOT_EQUAL(0, stats.uptime);
TEST_ASSERT_NOT_EQUAL(0, stats.idle_time);
return;
}

void test_cpu_load(void)
{

Thread thread(osPriorityNormal, MAX_THREAD_STACK);
Thread thread_stats(osPriorityNormal, MAX_THREAD_STACK);

thread.start(busy_thread);
thread_stats.start(get_cpu_usage);

// Steadily increase the system load
for (int count = 1; ; count++) {
Thread::wait(LOOP_TIME);
if (wait_time <= 0) {
break;
}
wait_time -= 1000; // usec
}
thread.terminate();
thread_stats.terminate();
}

Case cases[] = {
Case("Test CPU Info", test_cpu_info),
Case("Test CPU load", test_cpu_load)
};

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);
}
57 changes: 55 additions & 2 deletions hal/mbed_sleep_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,63 @@
#include "sleep_api.h"
#include "mbed_error.h"
#include "mbed_debug.h"
#include "mbed_stats.h"
#include "lp_ticker_api.h"
#include <limits.h>
#include <stdio.h>
#include "mbed_stats.h"


#if DEVICE_SLEEP

// deep sleep locking counter. A target is allowed to deep sleep if counter == 0
static uint16_t deep_sleep_lock = 0U;
static us_timestamp_t sleep_time = 0;
static us_timestamp_t deep_sleep_time = 0;

#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
static ticker_data_t *sleep_ticker = NULL;
#endif

static inline us_timestamp_t read_us(void)
{
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
if (NULL == sleep_ticker) {
sleep_ticker = (ticker_data_t *)get_lp_ticker_data();
}
return ticker_read_us(sleep_ticker);
#else
return 0;
#endif
}

us_timestamp_t mbed_time_idle(void)
{
return (sleep_time + deep_sleep_time);
}

us_timestamp_t mbed_uptime(void)
{
return read_us();
}

us_timestamp_t mbed_time_sleep(void)
{
return sleep_time;
}

us_timestamp_t mbed_time_deepsleep(void)
{
return deep_sleep_time;
}

#ifdef MBED_SLEEP_TRACING_ENABLED

// Number of drivers that can be stored in the structure
#define STATISTIC_COUNT 10

typedef struct sleep_statistic {
const char* identifier;
const char *identifier;
uint8_t count;
} sleep_statistic_t;

Expand Down Expand Up @@ -83,7 +125,7 @@ static void sleep_tracker_print_stats(void)
}
}

void sleep_tracker_lock(const char* const filename, int line)
void sleep_tracker_lock(const char *const filename, int line)
{
sleep_statistic_t *stat = sleep_tracker_find(filename);

Expand Down Expand Up @@ -147,16 +189,27 @@ void sleep_manager_sleep_auto(void)
sleep_tracker_print_stats();
#endif
core_util_critical_section_enter();
us_timestamp_t start = read_us();
bool deep = false;

// debug profile should keep debuggers attached, no deep sleep allowed
#ifdef MBED_DEBUG
hal_sleep();
#else
if (sleep_manager_can_deep_sleep()) {
deep = true;
hal_deepsleep();
} else {
hal_sleep();
}
#endif

us_timestamp_t end = read_us();
if (true == deep) {
deep_sleep_time += end - start;
} else {
sleep_time += end - start;
}
core_util_critical_section_exit();
}

Expand Down
29 changes: 29 additions & 0 deletions platform/mbed_power_mgmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "sleep_api.h"
#include "mbed_toolchain.h"
#include "hal/ticker_api.h"
#include <stdbool.h>

#ifdef __cplusplus
Expand Down Expand Up @@ -205,6 +206,34 @@ static inline void system_reset(void)
{
NVIC_SystemReset();
}

/** Provides the time spent in sleep mode since boot.
*
* @return Time spent in sleep
* @note Works only if platform supports LP ticker.
*/
us_timestamp_t mbed_time_sleep(void);

/** Provides the time spent in deep sleep mode since boot.
*
* @return Time spent in deep sleep
* @note Works only if platform supports LP ticker.
*/
us_timestamp_t mbed_time_deepsleep(void);

/** Provides the time spent in idle mode since boot.
*
* @return Idle thread time.
* @note Works only if platform supports LP ticker.
*/
us_timestamp_t mbed_time_idle(void);

/** Provides the time since the system is up i.e. boot.
*
* @return System uptime.
* @note Works only if platform supports LP ticker.
*/
us_timestamp_t mbed_uptime(void);

#ifdef __cplusplus
}
Expand Down
21 changes: 19 additions & 2 deletions platform/mbed_stats.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
#include "mbed_stats.h"
#include "mbed_power_mgmt.h"
#include <string.h>
#include <stdlib.h>
#include "mbed_assert.h"

#ifdef MBED_CONF_RTOS_PRESENT
#include "cmsis_os2.h"
#elif defined(MBED_STACK_STATS_ENABLED) || defined(MBED_THREAD_STATS_ENABLED)
#include "rtos_idle.h"
#elif defined(MBED_STACK_STATS_ENABLED) || defined(MBED_THREAD_STATS_ENABLED) || defined(MBED_CPU_STATS_ENABLED)
#warning Statistics are currently not supported without the rtos.
#endif

// note: mbed_stats_heap_get defined in mbed_alloc_wrappers.cpp
#if defined(MBED_CPU_STATS_ENABLED) && (!defined(DEVICE_LOWPOWERTIMER) || !defined(DEVICE_SLEEP))
#warning CPU statistics are not supported without low power timer support.
#endif

void mbed_stats_cpu_get(mbed_stats_cpu_t *stats)
{
MBED_ASSERT(stats != NULL);
memset(stats, 0, sizeof(mbed_stats_cpu_t));
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER) && defined(DEVICE_SLEEP)
stats->uptime = mbed_uptime();
stats->idle_time = mbed_time_idle();
stats->sleep_time = mbed_time_sleep();
stats->deep_sleep_time = mbed_time_deepsleep();
#endif
}

// note: mbed_stats_heap_get defined in mbed_alloc_wrappers.cpp
void mbed_stats_stack_get(mbed_stats_stack_t *stats)
{
MBED_ASSERT(stats != NULL);
Expand Down
19 changes: 19 additions & 0 deletions platform/mbed_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@
#define MBED_STATS_H
#include <stdint.h>
#include <stddef.h>
#include "hal/ticker_api.h"

#ifdef __cplusplus
extern "C" {
#endif

#ifdef MBED_ALL_STATS_ENABLED
#define MBED_STACK_STATS_ENABLED 1
#define MBED_CPU_STATS_ENABLED 1
#define MBED_HEAP_STATS_ENABLED 1
#define MBED_THREAD_STATS_ENABLED 1
#endif
Expand Down Expand Up @@ -82,6 +84,23 @@ 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);

/**
* struct mbed_stats_cpu_t definition
*/
typedef struct {
us_timestamp_t uptime; /**< Time since system is up and running */
us_timestamp_t idle_time; /**< Time spent in idle thread since system is up and running */
us_timestamp_t sleep_time; /**< Time spent in sleep since system is up and running */
us_timestamp_t deep_sleep_time; /**< Time spent in deep sleep since system is up and running */
} mbed_stats_cpu_t;

/**
* Fill the passed in CPU stat structure with CPU statistics.
*
* @param stats A pointer to the mbed_stats_cpu_t structure to fill
*/
void mbed_stats_cpu_get(mbed_stats_cpu_t *stats);

/**
* struct mbed_stats_thread_t definition
*/
Expand Down