BA / SerialCom

Fork of OmniWheels by Gustav Atmel

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 }