Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
main.cpp
00001 /* 00002 * Copyright (c) 2013-2017, ARM Limited, All Rights Reserved 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); you may 00006 * not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 #include "mbed.h" 00019 #include "greentea-client/test_env.h" 00020 #include "unity/unity.h" 00021 #include "utest/utest.h" 00022 #include "mbed_mem_trace.h" 00023 #include <stdlib.h> 00024 #include <stdio.h> 00025 #include <stdarg.h> 00026 00027 #ifndef MBED_MEM_TRACING_ENABLED 00028 #error [NOT_SUPPORTED] test not supported 00029 #endif 00030 00031 using utest::v1::Case; 00032 00033 00034 /******************************************************************************/ 00035 /* Helper functions and data structures */ 00036 /******************************************************************************/ 00037 00038 #define THREAD_STACK_SIZE 384 00039 #define NUM_TEST_THREADS 3 00040 00041 template<osPriority PRIORITY, uint32_t STACK_SIZE> 00042 class TestThread : public Thread { 00043 uint8_t stack[STACK_SIZE]; 00044 public: 00045 TestThread() : Thread(PRIORITY, STACK_SIZE, stack) { } 00046 }; 00047 00048 // This structure keeps data about the various memory allocation operations, 00049 // as traced by 'test_trace_cb' below. 00050 #define TEST_MAX_MEMORY_OPS 10 00051 00052 // Trace results for all possible operations 00053 typedef struct { 00054 uint8_t op; 00055 void *res; 00056 union { 00057 struct { 00058 size_t arg_size; 00059 } malloc_info; 00060 struct { 00061 void *arg_ptr; 00062 size_t arg_size; 00063 } realloc_info; 00064 struct { 00065 size_t arg_nmemb; 00066 size_t arg_size; 00067 } calloc_info; 00068 struct { 00069 void *arg_ptr; 00070 } free_info; 00071 }; 00072 } mem_trace_data_t; 00073 00074 // Memory operation statistics 00075 typedef struct { 00076 mem_trace_data_t op_data[TEST_MAX_MEMORY_OPS]; 00077 uint32_t total_ops; 00078 bool invalid_op, overflow; 00079 } stats_t; 00080 00081 static stats_t stats; 00082 00083 00084 // Clear all the memory statistics 00085 static void test_clear_stats() 00086 { 00087 memset(&stats, 0, sizeof(stats)); 00088 } 00089 00090 // Memory tracer callback that records each operation in "stats" (above) 00091 extern "C" void test_trace_cb(uint8_t op, void *res, void *caller, ...) 00092 { 00093 va_list va; 00094 mem_trace_data_t *pmem = stats.op_data + stats.total_ops; 00095 if (stats.total_ops >= TEST_MAX_MEMORY_OPS) { 00096 stats.overflow = true; 00097 return; 00098 } 00099 va_start(va, caller); 00100 pmem->op = op; 00101 pmem->res = res; 00102 switch(op) { 00103 case MBED_MEM_TRACE_MALLOC: 00104 pmem->malloc_info.arg_size = va_arg(va, size_t); 00105 break; 00106 00107 case MBED_MEM_TRACE_REALLOC: 00108 pmem->realloc_info.arg_ptr = va_arg(va, void *); 00109 pmem->realloc_info.arg_size = va_arg(va, size_t); 00110 break; 00111 00112 case MBED_MEM_TRACE_CALLOC: 00113 pmem->calloc_info.arg_nmemb = va_arg(va, size_t); 00114 pmem->calloc_info.arg_size = va_arg(va, size_t); 00115 break; 00116 00117 case MBED_MEM_TRACE_FREE: 00118 pmem->free_info.arg_ptr = va_arg(va, void *); 00119 break; 00120 00121 default: 00122 stats.invalid_op = true; 00123 } 00124 stats.total_ops ++; 00125 va_end(va); 00126 } 00127 00128 // Generic sanity checks for the tracer 00129 static void check_sanity(uint32_t expected_ops) 00130 { 00131 TEST_ASSERT_FALSE(stats.overflow); 00132 TEST_ASSERT_FALSE(stats.invalid_op); 00133 TEST_ASSERT_EQUAL_UINT32(expected_ops, stats.total_ops); 00134 } 00135 00136 // Check a "malloc" operation 00137 static void check_malloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_size) 00138 { 00139 TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_MALLOC, p->op); 00140 TEST_ASSERT_EQUAL_PTR(expected_res, p->res); 00141 TEST_ASSERT_EQUAL_UINT32(expected_arg_size, p->malloc_info.arg_size); 00142 } 00143 00144 // Check a "free" operation 00145 static void check_free_op(const mem_trace_data_t *p, void *expected_arg_ptr) 00146 { 00147 TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_FREE, p->op); 00148 TEST_ASSERT_EQUAL_PTR(expected_arg_ptr, p->free_info.arg_ptr); 00149 } 00150 00151 // Check a "realloc" operation 00152 static void check_realloc_op(const mem_trace_data_t *p, void *expected_res, void *expected_arg_ptr, size_t expected_arg_size) 00153 { 00154 TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_REALLOC, p->op); 00155 TEST_ASSERT_EQUAL_PTR(expected_res, p->res); 00156 TEST_ASSERT_EQUAL_UINT32(expected_arg_ptr, p->realloc_info.arg_ptr); 00157 TEST_ASSERT_EQUAL_UINT32(expected_arg_size, p->realloc_info.arg_size); 00158 } 00159 00160 // Check a "calloc" operation 00161 static void check_calloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_nmemb, size_t expected_arg_size) 00162 { 00163 TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_CALLOC, p->op); 00164 TEST_ASSERT_EQUAL_PTR(expected_res, p->res); 00165 TEST_ASSERT_EQUAL_UINT32(expected_arg_nmemb, p->calloc_info.arg_nmemb); 00166 TEST_ASSERT_EQUAL_UINT32(expected_arg_size, p->calloc_info.arg_size); 00167 } 00168 00169 // Memory tracer callback to test thread safety 00170 extern "C" void test_trace_cb_multithread(uint8_t op, void *res, void *caller, ...) 00171 { 00172 volatile static int trace_guard = 0; 00173 trace_guard++; 00174 TEST_ASSERT_TRUE_MESSAGE(trace_guard == 1, "Race condition occurred !!!!"); 00175 trace_guard--; 00176 } 00177 00178 // Thread function 00179 void malloc_free(volatile bool *thread_continue) 00180 { 00181 const size_t block_size = 126; 00182 00183 while(*thread_continue) { 00184 void *p = malloc(block_size); 00185 TEST_ASSERT_NOT_EQUAL(p, NULL); 00186 free(p); 00187 } 00188 } 00189 00190 00191 /** Test single malloc/free tracing 00192 * 00193 * Given a memory trace mechanism 00194 * When perform single memory allocation/deallocation using malloc/free 00195 * Then tracing matches the operations 00196 * 00197 */ 00198 static void test_case_single_malloc_free() 00199 { 00200 const uint32_t num_op = 2; 00201 const size_t block_size = 126; 00202 const mem_trace_data_t *pmem = stats.op_data; 00203 00204 test_clear_stats(); 00205 mbed_mem_trace_set_callback(test_trace_cb); 00206 00207 // Allocate a single memory block 00208 void *p = malloc(block_size); 00209 TEST_ASSERT_NOT_EQUAL(p, NULL); 00210 00211 // Free the memory block 00212 free(p); 00213 00214 // Stop tracing 00215 mbed_mem_trace_set_callback(NULL); 00216 00217 // Check tracer result 00218 check_sanity(num_op); 00219 check_malloc_op(pmem++, p, block_size); 00220 check_free_op(pmem, p); 00221 } 00222 00223 00224 /** Test all memory operations (malloc, realloc, free, calloc) tracing 00225 * 00226 * Given a memory trace mechanism 00227 * When perform all memory operations 00228 * Then tracing matches the operations 00229 * 00230 */ 00231 static void test_case_all_memory_ops() 00232 { 00233 const uint32_t num_op = 5; 00234 const size_t malloc_size = 40, realloc_size = 80, nmemb = 25, size = 10; 00235 const mem_trace_data_t *pmem = stats.op_data; 00236 00237 test_clear_stats(); 00238 mbed_mem_trace_set_callback(test_trace_cb); 00239 00240 // Allocate a single memory block, the realloc it 00241 void *p_malloc = malloc(malloc_size); 00242 TEST_ASSERT_NOT_EQUAL(p_malloc, NULL); 00243 void *p_realloc = realloc(p_malloc, realloc_size); 00244 TEST_ASSERT_NOT_EQUAL(p_realloc, NULL); 00245 00246 // Use calloc() now 00247 void *p_calloc = calloc(nmemb, size); 00248 TEST_ASSERT_NOT_EQUAL(p_calloc, NULL); 00249 00250 // Free the realloc() pointer first, then the calloc() one 00251 free(p_realloc); 00252 free(p_calloc); 00253 00254 // Stop tracing 00255 mbed_mem_trace_set_callback(NULL); 00256 00257 // Check tracer result 00258 check_sanity(num_op); 00259 check_malloc_op(pmem++, p_malloc, malloc_size); 00260 check_realloc_op(pmem++, p_realloc, p_malloc, realloc_size); 00261 check_calloc_op(pmem++, p_calloc, nmemb, size); 00262 check_free_op(pmem++, p_realloc); 00263 check_free_op(pmem, p_calloc); 00264 } 00265 00266 00267 /** Test that tracing is off when using a NULL callback 00268 * 00269 * Given a memory trace mechanism 00270 * When tracing is turned off 00271 * Then performed memory operations doesn't report any tracing 00272 * 00273 */ 00274 static void test_case_trace_off() 00275 { 00276 const uint32_t num_op = 0; 00277 const size_t malloc_size = 10; 00278 00279 test_clear_stats(); 00280 // We don't want any tracing 00281 mbed_mem_trace_set_callback(NULL); 00282 00283 // Allocate a buffer and free it 00284 void *p_malloc = malloc(malloc_size); 00285 TEST_ASSERT_NOT_EQUAL(p_malloc, NULL); 00286 free(p_malloc); 00287 00288 // Check that we didn't trace anything 00289 check_sanity(num_op); 00290 } 00291 00292 00293 /** Test partial tracing 00294 * 00295 * Given a memory trace mechanism 00296 * When perform memory operations while tracing is on then off and on again 00297 * Then tracing report only part of operations 00298 * 00299 */ 00300 static void test_case_partial_trace() 00301 { 00302 const uint32_t num_op = 2; 00303 const size_t malloc_size_1 = 20, malloc_size_2 = 30; 00304 const mem_trace_data_t *pmem = stats.op_data; 00305 00306 test_clear_stats(); 00307 00308 // Start tracing 00309 mbed_mem_trace_set_callback(test_trace_cb); 00310 00311 // Allocate a buffer 00312 void *p_malloc_1 = malloc(malloc_size_1); 00313 TEST_ASSERT_NOT_EQUAL(p_malloc_1, NULL); 00314 00315 // Disable tracing before freeing the first buffer 00316 mbed_mem_trace_set_callback(NULL); 00317 free(p_malloc_1); 00318 00319 // Allocate another buffer (still not traced) 00320 void *p_malloc_2 = malloc(malloc_size_2); 00321 TEST_ASSERT_NOT_EQUAL(p_malloc_2, NULL); 00322 00323 // Re-enable tracing 00324 mbed_mem_trace_set_callback(test_trace_cb); 00325 00326 // And free the second buffer (this operation should be tracer) 00327 free(p_malloc_2); 00328 00329 // Stop tracing 00330 mbed_mem_trace_set_callback(NULL); 00331 00332 // Check tracer result 00333 check_sanity(num_op); 00334 check_malloc_op(pmem++, p_malloc_1, malloc_size_1); 00335 check_free_op(pmem, p_malloc_2); 00336 } 00337 00338 00339 /** Test new/delete tracing 00340 * 00341 * Given a memory trace mechanism 00342 * When memory allocation/deallocation is performed using new/delete 00343 * Then tracing matches the operations 00344 * 00345 */ 00346 static void test_case_new_delete() 00347 { 00348 const uint32_t num_op = 4; 00349 const mem_trace_data_t *pmem = stats.op_data; 00350 00351 test_clear_stats(); 00352 00353 // Start tracing 00354 mbed_mem_trace_set_callback(test_trace_cb); 00355 00356 // Test new, new[], delete and delete[] 00357 int *p_int = new int; 00358 int *p_int_array = new int[10]; 00359 delete p_int; 00360 delete[] p_int_array; 00361 00362 // Stop tracing 00363 mbed_mem_trace_set_callback(NULL); 00364 00365 // Check tracer result 00366 check_sanity(num_op); 00367 check_malloc_op(pmem++, p_int, sizeof(int)); 00368 check_malloc_op(pmem++, p_int_array, 10 * sizeof(int)); 00369 check_free_op(pmem++, p_int); 00370 check_free_op(pmem, p_int_array); 00371 } 00372 00373 00374 /** Test tracing thread safety 00375 * 00376 * Given a memory trace mechanism and multiple threads are started in parallel 00377 * When each of the threads perform memory allocation/deallocation (thus uses memory trace mechanisms) 00378 * Then tracing is protected against simultaneous multithreaded access 00379 * 00380 */ 00381 static void test_case_multithread_malloc_free() 00382 { 00383 const uint32_t wait_time_us = 10000; 00384 volatile bool threads_continue; 00385 TestThread<osPriorityNormal, THREAD_STACK_SIZE> threads[NUM_TEST_THREADS]; 00386 00387 mbed_mem_trace_set_callback(test_trace_cb_multithread); 00388 00389 threads_continue = true; 00390 for (int i = 0; i < NUM_TEST_THREADS; i++) { 00391 threads[i].start(callback(malloc_free, &threads_continue)); 00392 } 00393 00394 Thread::wait(wait_time_us); 00395 threads_continue = false; 00396 00397 for (int i = 0; i < NUM_TEST_THREADS; i++) { 00398 threads[i].join(); 00399 } 00400 00401 mbed_mem_trace_set_callback(NULL); 00402 } 00403 00404 00405 00406 static Case cases[] = 00407 { 00408 Case("Test single malloc/free trace", test_case_single_malloc_free), 00409 Case("Test all memory operations trace", test_case_all_memory_ops), 00410 Case("Test trace off", test_case_trace_off), 00411 Case("Test partial trace", test_case_partial_trace), 00412 Case("Test new/delete trace", test_case_new_delete), 00413 Case("Test multithreaded trace", test_case_multithread_malloc_free) 00414 }; 00415 00416 static utest::v1::status_t greentea_test_setup(const size_t number_of_cases) 00417 { 00418 GREENTEA_SETUP(15, "default_auto"); 00419 return utest::v1::greentea_test_setup_handler(number_of_cases); 00420 } 00421 00422 static utest::v1::Specification specification(greentea_test_setup, cases, utest::v1::greentea_test_teardown_handler); 00423 00424 int main() 00425 { 00426 // Disable stdout buffering to prevent any unwanted allocations 00427 setvbuf(stdout, NULL, _IONBF, 0); 00428 00429 return !utest::v1::Harness::run(specification); 00430 }
Generated on Fri Jul 22 2022 04:53:55 by
1.7.2
