Skip to content

Commit 3420ff7

Browse files
author
deepikabhavnani
committed
CPU statistics addition
API to get CPU stats like sleep/deepsleep time, uptime and idle time. These can be used by application to know the CPU Usage runtime.
1 parent e88f431 commit 3420ff7

File tree

6 files changed

+229
-16
lines changed

6 files changed

+229
-16
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
2+
/* mbed Microcontroller Library
3+
* Copyright (c) 2018 ARM Limited
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "greentea-client/test_env.h"
19+
#include "unity/unity.h"
20+
#include "utest/utest.h"
21+
22+
#include "mbed.h"
23+
24+
#if !defined(MBED_CPU_STATS_ENABLED)
25+
#error [NOT_SUPPORTED] test not supported
26+
#endif
27+
28+
using namespace utest::v1;
29+
30+
DigitalOut led1(LED1);
31+
32+
#define MAX_THREAD_STACK 384
33+
#define SAMPLE_TIME 1000 // msec
34+
#define LOOP_TIME 2000 // msec
35+
36+
static int32_t wait_time = 5000;
37+
38+
static void busy_thread()
39+
{
40+
volatile uint64_t i = ~0;
41+
42+
while(i--) {
43+
led1 = !led1;
44+
wait_us(wait_time);
45+
}
46+
}
47+
48+
void get_cpu_usage()
49+
{
50+
static uint64_t prev_idle_time = 0;
51+
mbed_stats_cpu_t stats;
52+
mbed_stats_cpu_get(&stats);
53+
54+
uint64_t diff = (stats.idle_time - prev_idle_time);
55+
uint8_t usage = 100 - ((diff * 100) / (SAMPLE_TIME*1000));
56+
prev_idle_time = stats.idle_time;
57+
58+
TEST_ASSERT_NOT_EQUAL(0, usage);
59+
}
60+
61+
void test_cpu_info(void)
62+
{
63+
mbed_stats_cpu_t stats;
64+
Thread::wait(0.1);
65+
TEST_ASSERT_NOT_EQUAL(0, stats.uptime);
66+
TEST_ASSERT_NOT_EQUAL(0, stats.idle_time);
67+
return;
68+
}
69+
70+
void test_cpu_load(void)
71+
{
72+
EventQueue *stats_queue = mbed_event_queue();
73+
int id = stats_queue->call_every(SAMPLE_TIME, get_cpu_usage);
74+
Thread thread(osPriorityNormal, MAX_THREAD_STACK);
75+
76+
thread.start(busy_thread);
77+
78+
// Steadily increase the system load
79+
for (int count = 1; ; count++) {
80+
Thread::wait(LOOP_TIME);
81+
if (wait_time <= 0) {
82+
break;
83+
}
84+
wait_time -= 1000; // usec
85+
}
86+
thread.terminate();
87+
stats_queue->cancel(id);
88+
}
89+
90+
Case cases[] = {
91+
Case("Test CPU Info", test_cpu_info),
92+
Case("Test CPU load", test_cpu_load)
93+
};
94+
95+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
96+
{
97+
GREENTEA_SETUP(20, "default_auto");
98+
return greentea_test_setup_handler(number_of_cases);
99+
}
100+
101+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
102+
103+
int main()
104+
{
105+
Harness::run(specification);
106+
}

hal/mbed_sleep_manager.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,62 @@
2020
#include "sleep_api.h"
2121
#include "mbed_error.h"
2222
#include "mbed_debug.h"
23+
#include "mbed_stats.h"
24+
#include "lp_ticker_api.h"
2325
#include <limits.h>
2426
#include <stdio.h>
27+
#include "mbed_stats.h"
28+
2529

2630
#if DEVICE_SLEEP
2731

2832
// deep sleep locking counter. A target is allowed to deep sleep if counter == 0
2933
static uint16_t deep_sleep_lock = 0U;
34+
static uint64_t sleep_time = 0;
35+
static uint64_t deep_sleep_time = 0;
36+
37+
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
38+
static ticker_data_t *sleep_ticker = NULL;
39+
#endif
40+
41+
static inline uint64_t read_us(void)
42+
{
43+
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
44+
if (NULL == sleep_ticker) {
45+
sleep_ticker = (ticker_data_t*) get_lp_ticker_data();
46+
}
47+
return ticker_read_us(sleep_ticker);
48+
#else
49+
return 0;
50+
#endif
51+
}
52+
53+
uint64_t mbed_time_idle(void)
54+
{
55+
return (sleep_time+deep_sleep_time);
56+
}
57+
58+
uint64_t mbed_uptime(void)
59+
{
60+
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER)
61+
if (NULL == sleep_ticker) {
62+
sleep_ticker = (ticker_data_t*) get_lp_ticker_data();
63+
}
64+
return ticker_read_us(sleep_ticker);
65+
#else
66+
return 0;
67+
#endif
68+
}
69+
70+
uint64_t mbed_time_sleep(void)
71+
{
72+
return sleep_time;
73+
}
74+
75+
uint64_t mbed_time_deepsleep(void)
76+
{
77+
return deep_sleep_time;
78+
}
3079

3180
#ifdef MBED_SLEEP_TRACING_ENABLED
3281

@@ -147,16 +196,27 @@ void sleep_manager_sleep_auto(void)
147196
sleep_tracker_print_stats();
148197
#endif
149198
core_util_critical_section_enter();
199+
uint64_t start = read_us();
200+
bool deep = false;
201+
150202
// debug profile should keep debuggers attached, no deep sleep allowed
151203
#ifdef MBED_DEBUG
152204
hal_sleep();
153205
#else
154206
if (sleep_manager_can_deep_sleep()) {
207+
deep = true;
155208
hal_deepsleep();
156209
} else {
157210
hal_sleep();
158211
}
159212
#endif
213+
214+
uint64_t end = read_us();
215+
if(true == deep) {
216+
deep_sleep_time += end - start;
217+
} else {
218+
sleep_time += end - start;
219+
}
160220
core_util_critical_section_exit();
161221
}
162222

platform/mbed_power_mgmt.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,32 @@ static inline void system_reset(void)
205205
{
206206
NVIC_SystemReset();
207207
}
208+
209+
/** Provides the time spent in sleep mode, since system is up and running
210+
*
211+
* @return Time spent in sleep
212+
*/
213+
uint64_t mbed_time_sleep(void);
214+
215+
/** Provides the time spent in deep sleep mode, since system is up and running
216+
*
217+
* @return Time spent in deep sleep
218+
*/
219+
uint64_t mbed_time_deepsleep(void);
220+
221+
/** Provides the time spent in idle thread since the system is up
222+
*
223+
* @return Idle thread time.
224+
*/
225+
uint64_t mbed_time_idle(void);
226+
227+
228+
/** Provides the time since the system is up and running
229+
*
230+
* @return System uptime.
231+
*/
232+
uint64_t mbed_uptime(void);
233+
208234

209235
#ifdef __cplusplus
210236
}

platform/mbed_stats.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,33 @@
11
#include "mbed_stats.h"
2+
#include "mbed_power_mgmt.h"
23
#include <string.h>
34
#include <stdlib.h>
45
#include "mbed_assert.h"
56

67
#ifdef MBED_CONF_RTOS_PRESENT
78
#include "cmsis_os2.h"
8-
#elif defined(MBED_STACK_STATS_ENABLED) || defined(MBED_THREAD_STATS_ENABLED)
9+
#include "rtos_idle.h"
10+
#elif defined(MBED_STACK_STATS_ENABLED) || defined(MBED_THREAD_STATS_ENABLED) || defined(MBED_CPU_STATS_ENABLED)
911
#warning Statistics are currently not supported without the rtos.
1012
#endif
1113

12-
// note: mbed_stats_heap_get defined in mbed_alloc_wrappers.cpp
14+
#if defined(MBED_CPU_STATS_ENABLED) && (!defined(DEVICE_LOWPOWERTIMER) || !defined(DEVICE_SLEEP))
15+
#warning CPU statistics are not supported without low power timer support.
16+
#endif
17+
18+
void mbed_stats_cpu_get(mbed_stats_cpu_t *stats)
19+
{
20+
MBED_ASSERT(stats != NULL);
21+
memset(stats, 0, sizeof(mbed_stats_cpu_t));
22+
#if defined(MBED_CPU_STATS_ENABLED) && defined(DEVICE_LOWPOWERTIMER) && defined(DEVICE_SLEEP)
23+
stats->uptime = mbed_uptime();
24+
stats->idle_time = mbed_time_idle();
25+
stats->sleep_time = mbed_time_sleep();
26+
stats->deep_sleep_time = mbed_time_deepsleep();
27+
#endif
28+
}
1329

30+
// note: mbed_stats_heap_get defined in mbed_alloc_wrappers.cpp
1431
void mbed_stats_stack_get(mbed_stats_stack_t *stats)
1532
{
1633
MBED_ASSERT(stats != NULL);

platform/mbed_stats.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extern "C" {
3131

3232
#ifdef MBED_ALL_STATS_ENABLED
3333
#define MBED_STACK_STATS_ENABLED 1
34+
#define MBED_CPU_STATS_ENABLED 1
3435
#define MBED_HEAP_STATS_ENABLED 1
3536
#define MBED_THREAD_STATS_ENABLED 1
3637
#endif
@@ -82,6 +83,23 @@ void mbed_stats_stack_get(mbed_stats_stack_t *stats);
8283
*/
8384
size_t mbed_stats_stack_get_each(mbed_stats_stack_t *stats, size_t count);
8485

86+
/**
87+
* struct mbed_stats_cpu_t definition
88+
*/
89+
typedef struct {
90+
uint64_t uptime; /**< Time since system is up and running */
91+
uint64_t idle_time; /**< Time spent in idle thread since system is up and running */
92+
uint64_t sleep_time; /**< Time spent in sleep since system is up and running */
93+
uint64_t deep_sleep_time; /**< Time spent in deep sleep since system is up and running */
94+
} mbed_stats_cpu_t;
95+
96+
/**
97+
* Fill the passed in CPU stat structure with CPU statistics.
98+
*
99+
* @param stats A pointer to the mbed_stats_cpu_t structure to fill
100+
*/
101+
void mbed_stats_cpu_get(mbed_stats_cpu_t *stats);
102+
85103
/**
86104
* struct mbed_stats_thread_t definition
87105
*/

rtos/TARGET_CORTEX/mbed_rtx_idle.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,6 @@ extern "C" {
3434

3535
using namespace mbed;
3636

37-
static const ticker_data_t *const cpu_usage_ticker = get_lp_ticker_data();
38-
static uint32_t idle_time = 0;
39-
40-
extern uint32_t mbed_time_idle(void)
41-
{
42-
return idle_time;
43-
}
44-
4537
#ifdef MBED_TICKLESS
4638

4739
#include "rtos/TARGET_CORTEX/SysTimer.h"
@@ -106,7 +98,6 @@ static void default_idle_hook(void)
10698
uint32_t ticks_to_sleep = osKernelSuspend();
10799
os_timer->suspend(ticks_to_sleep);
108100

109-
uint32_t start = ticker_read_us(cpu_usage_ticker);
110101
bool event_pending = false;
111102
while (!os_timer->suspend_time_passed() && !event_pending) {
112103

@@ -122,8 +113,6 @@ static void default_idle_hook(void)
122113
__ISB();
123114
}
124115
osKernelResume(os_timer->resume());
125-
uint32_t end = ticker_read_us(cpu_usage_ticker);
126-
idle_time += end - start;
127116
}
128117

129118
#elif defined(FEATURE_UVISOR)
@@ -140,12 +129,9 @@ static void default_idle_hook(void)
140129
{
141130
// critical section to complete sleep with locked deepsleep
142131
core_util_critical_section_enter();
143-
uint32_t start = ticker_read_us(cpu_usage_ticker);
144132
sleep_manager_lock_deep_sleep();
145133
sleep();
146134
sleep_manager_unlock_deep_sleep();
147-
uint32_t end = ticker_read_us(cpu_usage_ticker);
148-
idle_time += end - start;
149135
core_util_critical_section_exit();
150136
}
151137

0 commit comments

Comments
 (0)