Skip to content

Commit bc0c85b

Browse files
authored
Merge pull request #2442 from c1728p9/heap_stats
Malloc heap info
2 parents dda7f7d + f21adc4 commit bc0c85b

File tree

7 files changed

+447
-6
lines changed

7 files changed

+447
-6
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);

features/frameworks/utest/source/utest_harness.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,12 @@ void Harness::raise_failure(const failure_reason_t reason)
167167
if (test_cases == NULL) return;
168168

169169
utest::v1::status_t fail_status = STATUS_ABORT;
170+
if (handlers.test_failure) handlers.test_failure(failure_t(reason, location));
171+
if (handlers.case_failure) fail_status = handlers.case_failure(case_current, failure_t(reason, location));
172+
170173
{
171174
UTEST_ENTER_CRITICAL_SECTION;
172175

173-
if (handlers.test_failure) handlers.test_failure(failure_t(reason, location));
174-
if (handlers.case_failure) fail_status = handlers.case_failure(case_current, failure_t(reason, location));
175176
if (fail_status != STATUS_IGNORE) case_failed++;
176177

177178
if ((fail_status == STATUS_ABORT) && case_timeout_handle)

features/storage/FEATURE_STORAGE/cfstore/source/cfstore_test.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,11 @@ int32_t cfstore_test_delete_all(void)
374374
CFSTORE_ERRLOG("%s:Error: failed to delete key_name=%s, len=%d\r\n", __func__, key_name, (int) len);
375375
return ret;
376376
}
377-
CFSTORE_HANDLE_SWAP(prev, next);
377+
ret = drv->Close(next);
378+
if(ret < ARM_DRIVER_OK){
379+
CFSTORE_ERRLOG("%s:Error: failed to close key_name=%s, len=%d\r\n", __func__, key_name, (int) len);
380+
return ret;
381+
}
378382
}
379383
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
380384
/* as expected, no more keys have been found by the Find()*/

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)