Skip to content

Commit 6a31ffb

Browse files
committed
Heap statistics
Keep track of the current size allocated, maximum size allocated, number of allocations, failed allocations and total size allocated for both GCC and ARM. Report the maximum size allocated at the end of testing. Also, add a test to verify heap metrics are working as expected.
1 parent dda7f7d commit 6a31ffb

File tree

5 files changed

+439
-3
lines changed

5 files changed

+439
-3
lines changed

TESTS/mbed_drivers/stats/main.cpp

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6+
* 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, WITHOUT
13+
* 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+
#include "mbed.h"
18+
#include "greentea-client/test_env.h"
19+
#include "unity/unity.h"
20+
#include "utest/utest.h"
21+
#include "mbed_stats.h"
22+
#include <stdlib.h>
23+
#include <stdio.h>
24+
25+
#if !defined(MBED_HEAP_STATS_ENABLED) || !MBED_HEAP_STATS_ENABLED || defined(__ICCARM__)
26+
#error [NOT_SUPPORTED] test not supported
27+
#endif
28+
29+
using namespace utest::v1;
30+
31+
#define ALLOCATION_SIZE_DEFAULT 564
32+
#define ALLOCATION_SIZE_SMALL 124
33+
#define ALLOCATION_SIZE_LARGE 790
34+
#define ALLOCATION_SIZE_FAIL (1024 * 1024 *1024)
35+
36+
typedef void* (*malloc_cb_t) (uint32_t size);
37+
38+
static void* thunk_malloc(uint32_t size);
39+
static void* thunk_calloc_1(uint32_t size);
40+
static void* thunk_calloc_4(uint32_t size);
41+
static void* thunk_realloc(uint32_t size);
42+
43+
malloc_cb_t malloc_thunk_array[] = {
44+
thunk_malloc,
45+
thunk_calloc_1,
46+
thunk_calloc_4,
47+
thunk_realloc,
48+
};
49+
50+
void test_case_malloc_free_size()
51+
{
52+
printf("Initial print to setup stdio buffers\n");
53+
mbed_stats_heap_t stats_start;
54+
mbed_stats_heap_t stats_current;
55+
void *data;
56+
57+
mbed_stats_heap_get(&stats_start);
58+
59+
for (uint32_t i = 0; i < sizeof(malloc_thunk_array) / sizeof(malloc_cb_t); i++) {
60+
61+
// Allocate memory and assert size change
62+
data = malloc_thunk_array[i](ALLOCATION_SIZE_DEFAULT);
63+
TEST_ASSERT(data != NULL);
64+
mbed_stats_heap_get(&stats_current);
65+
uint32_t increase = stats_current.current_size - stats_start.current_size;
66+
TEST_ASSERT_EQUAL_UINT32(ALLOCATION_SIZE_DEFAULT, increase);
67+
TEST_ASSERT_EQUAL_UINT32(stats_start.total_size + ALLOCATION_SIZE_DEFAULT * (i + 1), stats_current.total_size);
68+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_cnt + 1, stats_current.alloc_cnt);
69+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_fail_cnt, stats_current.alloc_fail_cnt);
70+
71+
// Free memory and assert back to starting size
72+
free(data);
73+
mbed_stats_heap_get(&stats_current);
74+
TEST_ASSERT_EQUAL_UINT32(stats_start.current_size, stats_current.current_size);
75+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_cnt, stats_current.alloc_cnt);
76+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_fail_cnt, stats_current.alloc_fail_cnt);
77+
}
78+
}
79+
80+
void test_case_allocate_zero()
81+
{
82+
mbed_stats_heap_t stats_start;
83+
mbed_stats_heap_t stats_current;
84+
void *data;
85+
86+
mbed_stats_heap_get(&stats_start);
87+
88+
for (uint32_t i = 0; i < sizeof(malloc_thunk_array) / sizeof(malloc_cb_t); i++) {
89+
90+
// Allocate memory and assert size change
91+
data = malloc_thunk_array[i](0);
92+
// Return can be NULL
93+
mbed_stats_heap_get(&stats_current);
94+
TEST_ASSERT_EQUAL_UINT32(stats_start.current_size, stats_current.current_size);
95+
TEST_ASSERT_EQUAL_UINT32(stats_start.total_size, stats_current.total_size);
96+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_fail_cnt, stats_current.alloc_fail_cnt);
97+
98+
// Free memory and assert back to starting size
99+
free(data);
100+
mbed_stats_heap_get(&stats_current);
101+
TEST_ASSERT_EQUAL_UINT32(stats_start.current_size, stats_current.current_size);
102+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_cnt, stats_current.alloc_cnt);
103+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_fail_cnt, stats_current.alloc_fail_cnt);
104+
}
105+
}
106+
107+
void test_case_allocate_fail()
108+
{
109+
mbed_stats_heap_t stats_start;
110+
mbed_stats_heap_t stats_current;
111+
void *data;
112+
113+
mbed_stats_heap_get(&stats_start);
114+
115+
for (uint32_t i = 0; i < sizeof(malloc_thunk_array) / sizeof(malloc_cb_t); i++) {
116+
117+
// Trigger a failure by trying to allocate a buffer that won't fit
118+
data = malloc_thunk_array[i](ALLOCATION_SIZE_FAIL);
119+
TEST_ASSERT(data == NULL);
120+
mbed_stats_heap_get(&stats_current);
121+
TEST_ASSERT_EQUAL_UINT32(stats_start.current_size, stats_current.current_size);
122+
TEST_ASSERT_EQUAL_UINT32(stats_start.total_size, stats_current.total_size);
123+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_cnt, stats_current.alloc_cnt);
124+
TEST_ASSERT_EQUAL_UINT32(stats_start.alloc_fail_cnt + i + 1, stats_current.alloc_fail_cnt);
125+
}
126+
}
127+
128+
static void* thunk_malloc(uint32_t size)
129+
{
130+
printf("Malloc thunk\n");
131+
return malloc(size);
132+
}
133+
134+
static void* thunk_calloc_1(uint32_t size)
135+
{
136+
printf("Calloc thunk 1 byte\n");
137+
return calloc(size / 1, 1);
138+
}
139+
140+
static void* thunk_calloc_4(uint32_t size)
141+
{
142+
printf("Calloc thunk 4 bytes\n");
143+
return calloc(size / 4, 4);
144+
}
145+
146+
147+
static void* thunk_realloc(uint32_t size)
148+
{
149+
printf("Realloc thunk\n");
150+
return realloc(NULL, size);
151+
}
152+
153+
void test_case_realloc_size()
154+
{
155+
mbed_stats_heap_t stats_start;
156+
mbed_stats_heap_t stats_current;
157+
uint32_t increase;
158+
void *data;
159+
160+
mbed_stats_heap_get(&stats_start);
161+
162+
// Allocate memory and assert size change
163+
data = realloc(NULL, ALLOCATION_SIZE_DEFAULT);
164+
TEST_ASSERT(data != NULL);
165+
mbed_stats_heap_get(&stats_current);
166+
increase = stats_current.current_size - stats_start.current_size;
167+
TEST_ASSERT_EQUAL_UINT32(increase, ALLOCATION_SIZE_DEFAULT);
168+
169+
// Decrease size and assert size change
170+
data = realloc(data, ALLOCATION_SIZE_SMALL);
171+
TEST_ASSERT(data != NULL);
172+
mbed_stats_heap_get(&stats_current);
173+
increase = stats_current.current_size - stats_start.current_size;
174+
TEST_ASSERT_EQUAL_UINT32(increase, ALLOCATION_SIZE_SMALL);
175+
176+
// Increase size and assert size change
177+
data = realloc(data, ALLOCATION_SIZE_LARGE);
178+
TEST_ASSERT(data != NULL);
179+
mbed_stats_heap_get(&stats_current);
180+
increase = stats_current.current_size - stats_start.current_size;
181+
TEST_ASSERT_EQUAL_UINT32(increase, ALLOCATION_SIZE_LARGE);
182+
183+
// Free memory and assert back to starting size
184+
free(data);
185+
mbed_stats_heap_get(&stats_current);
186+
TEST_ASSERT_EQUAL_UINT32(stats_start.current_size, stats_current.current_size);
187+
}
188+
189+
Case cases[] = {
190+
Case("malloc and free size", test_case_malloc_free_size),
191+
Case("allocate size zero", test_case_allocate_zero),
192+
Case("allocation failure", test_case_allocate_fail),
193+
Case("realloc size", test_case_realloc_size),
194+
};
195+
196+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
197+
{
198+
GREENTEA_SETUP(20, "default_auto");
199+
return greentea_test_setup_handler(number_of_cases);
200+
}
201+
202+
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
203+
204+
int main()
205+
{
206+
Harness::run(specification);
207+
}

features/frameworks/utest/source/utest_greentea_handlers.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "greentea-client/test_env.h"
2222
#include "utest/utest_stack_trace.h"
2323
#include "utest/utest_serial.h"
24+
#include "mbed_stats.h"
2425

2526
using namespace utest::v1;
2627

@@ -105,7 +106,10 @@ utest::v1::status_t utest::v1::greentea_test_setup_handler(const size_t number_o
105106
void utest::v1::greentea_test_teardown_handler(const size_t passed, const size_t failed, const failure_t failure)
106107
{
107108
UTEST_LOG_FUNCTION();
109+
mbed_stats_heap_t heap_stats;
108110
verbose_test_teardown_handler(passed, failed, failure);
111+
mbed_stats_heap_get(&heap_stats);
112+
greentea_send_kv("max_heap_usage",heap_stats.max_size);
109113
greentea_send_kv(TEST_ENV_TESTCASE_SUMMARY, passed, failed);
110114
int result = !(failed || (failure.reason && !(failure.reason & REASON_IGNORE)));
111115
GREENTEA_TESTSUITE_RESULT(result);

hal/api/mbed_stats.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2016-2016 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#ifndef MBED_STATS_H
17+
#define MBED_STATS_H
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
typedef struct {
24+
uint32_t current_size; /**< Bytes allocated currently. */
25+
uint32_t max_size; /**< Max bytes allocated at a given time. */
26+
uint32_t total_size; /**< Cumulative sum of bytes ever allocated. */
27+
uint32_t alloc_cnt; /**< Current number of allocations. */
28+
uint32_t alloc_fail_cnt; /**< Number of failed allocations. */
29+
} mbed_stats_heap_t;
30+
31+
/**
32+
* Fill the passed in structure with heap stats.
33+
*/
34+
void mbed_stats_heap_get(mbed_stats_heap_t *stats);
35+
36+
#ifdef __cplusplus
37+
}
38+
#endif
39+
40+
#endif

0 commit comments

Comments
 (0)