From b284ac32b53f500602d52d349e2bd7e84c43068c Mon Sep 17 00:00:00 2001 From: Michal Jerzy Wierzbicki Date: Wed, 3 Oct 2018 04:00:30 +0200 Subject: [PATCH] debugability: Macro Metaprogramming Refactor Added macro functions to make repetitive, nearly identical functions more maintainable via metaprogramming. They generate code in pre-compile, conceptually similar to C++17 if-constexpr. sof/trace, host/trace: rewrote _trace_event/d+ functions using preproc.h. test/cmocka/include/test_group_generator: rewrote macros to not conflict with new ones. Added unit tests to check whether more advanced and less obvious macros do in fact work. Signed-off-by: Michal Jerzy Wierzbicki --- src/host/trace.c | 187 ++--- src/include/sof/preproc-private-dec.h | 121 ++++ src/include/sof/preproc-private-inc.h | 121 ++++ src/include/sof/preproc-private.h | 265 +++++++ src/include/sof/preproc.h | 185 +++++ src/include/sof/sof.h | 4 +- src/include/sof/trace.h | 163 +++-- src/lib/trace.c | 753 ++++---------------- test/cmocka/Makefile.am | 27 + test/cmocka/include/test_group_generator.h | 33 +- test/cmocka/include/test_simple_macro.h | 37 + test/cmocka/src/debugability/macros.c | 171 +++++ test/cmocka/src/lib/preproc/concat.c | 86 +++ test/cmocka/src/lib/preproc/defer.c | 96 +++ test/cmocka/src/lib/preproc/get_arg.c | 70 ++ test/cmocka/src/lib/preproc/seq.c | 101 +++ test/cmocka/src/lib/preproc/varargs_count.c | 85 +++ 17 files changed, 1680 insertions(+), 825 deletions(-) create mode 100644 src/include/sof/preproc-private-dec.h create mode 100644 src/include/sof/preproc-private-inc.h create mode 100644 src/include/sof/preproc-private.h create mode 100644 src/include/sof/preproc.h create mode 100644 test/cmocka/include/test_simple_macro.h create mode 100644 test/cmocka/src/debugability/macros.c create mode 100644 test/cmocka/src/lib/preproc/concat.c create mode 100644 test/cmocka/src/lib/preproc/defer.c create mode 100644 test/cmocka/src/lib/preproc/get_arg.c create mode 100644 test/cmocka/src/lib/preproc/seq.c create mode 100644 test/cmocka/src/lib/preproc/varargs_count.c diff --git a/src/host/trace.c b/src/host/trace.c index 308affe7f797..5c2c79386183 100644 --- a/src/host/trace.c +++ b/src/host/trace.c @@ -31,6 +31,7 @@ * Ranjani Sridharan */ +#include #include #include #include @@ -142,134 +143,84 @@ static char *get_trace_class(uint32_t trace_class) return "value"; } -/* print trace event */ -void _trace_event0(uint32_t event) -{ - char a, b, c; - char *trace_class = NULL; - - if (test_bench_trace > 0) { - a = event & 0xff; - b = (event >> 8) & 0xff; - c = (event >> 16) & 0xff; +#define META_SEQ_STEP_param_procD(i, _) META_CONCAT(param, i) %d - /* look up subsystem from trace class table */ - trace_class = strdup(get_trace_class(event >> 24)); - - /* print trace event stderr*/ - if (strcmp(trace_class, "value") == 0) - fprintf(stderr, "Trace value %d\n", event); - else - fprintf(stderr, "Trace %s %c%c%c\n", trace_class, - c, b, a); - } - - free(trace_class); -} - -void _trace_event_mbox_atomic0(uint32_t event) -{ - _trace_event0(event); -} +#define HOST_TRACE_EVENT_NTH(postfix, vararg_count)\ + META_FUNC_WITH_VARARGS(_trace_event, postfix, void,\ + META_CONCAT(, uint32_t event),\ + vararg_count, META_SEQ_STEP_param_uint32_t) /* print trace event */ -void _trace_event1(uint32_t event, uint32_t param) -{ - char a, b, c; - char *trace_class = NULL; - - if (test_bench_trace > 0) { - a = event & 0xff; - b = (event >> 8) & 0xff; - c = (event >> 16) & 0xff; - - /* look up subsystem from trace class table */ - trace_class = strdup(get_trace_class(event >> 24)); - - /* print trace event stderr*/ - if (strcmp(trace_class, "value") == 0) - fprintf(stderr, "Trace value %d, param1 %d\n", event, - param); - else - fprintf(stderr, "Trace %s %c%c%c\n", trace_class, - c, b, a); - } - - free(trace_class); +#define HOST_TRACE_EVENT_NTH_IMPL(arg_count)\ +HOST_TRACE_EVENT_NTH(, arg_count)\ +{\ + char a, b, c;\ + \ + if (test_bench_trace > 0) {\ + /* look up subsystem from trace class table */\ + char *trace_class = strdup(get_trace_class(event >> 24));\ + \ + a = event & 0xff;\ + b = (event >> 8) & 0xff;\ + c = (event >> 16) & 0xff;\ + \ + /* print trace event stderr*/\ + if (!strcmp(trace_class, "value"))\ + fprintf(stderr,\ + "Trace value %d, "META_QUOTE(\ + META_SEQ_FROM_0_TO(\ + arg_count, META_SEQ_STEP_param_procD\ + ))"\n"\ + , event META_SEQ_FROM_0_TO(arg_count, META_SEQ_STEP_param));\ + else\ + fprintf(stderr,\ + "Trace %s %c%c%c\n"\ + , trace_class, c, b, a);\ + if (trace_class)\ + free(trace_class);\ + }\ +}\ +HOST_TRACE_EVENT_NTH(_mbox_atomic, arg_count)\ +{\ + META_CONCAT(_trace_event, arg_count)\ + (event META_SEQ_FROM_0_TO(arg_count,META_SEQ_STEP_param));\ } -void _trace_event_mbox_atomic1(uint32_t event, uint32_t param) -{ - _trace_event1(event, param); -} - -/* print trace event */ -void _trace_event2(uint32_t event, uint32_t param1, uint32_t param2) -{ - char a, b, c; - char *trace_class = NULL; - - if (test_bench_trace > 0) { - a = event & 0xff; - b = (event >> 8) & 0xff; - c = (event >> 16) & 0xff; - - /* look up subsystem from trace class table */ - trace_class = strdup(get_trace_class(event >> 24)); - - /* print trace event stderr*/ - if (strcmp(trace_class, "value") == 0) - fprintf(stderr, - "Trace value %d, param1 %d param2 %d\n", - event, param1, param2); - else - fprintf(stderr, "Trace %s %c%c%c\n", trace_class, - c, b, a); - } - - free(trace_class); -} - -void _trace_event_mbox_atomic2(uint32_t event, uint32_t param1, - uint32_t param2) -{ - _trace_event2(event, param1, param2); -} - -/* print trace event */ -void _trace_event3(uint32_t event, uint32_t param1, uint32_t param2, - uint32_t param3) -{ - char a, b, c; - char *trace_class = NULL; +/* Implementation of + * void _trace_event0( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic0(uint32_t log_entry, uint32_t params...) {...} + */ +HOST_TRACE_EVENT_NTH_IMPL(0); - if (test_bench_trace > 0) { - a = event & 0xff; - b = (event >> 8) & 0xff; - c = (event >> 16) & 0xff; +/* Implementation of + * void _trace_event1( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic1(uint32_t log_entry, uint32_t params...) {...} + */ +HOST_TRACE_EVENT_NTH_IMPL(1); - /* look up subsystem from trace class table */ - trace_class = strdup(get_trace_class(event >> 24)); +/* Implementation of + * void _trace_event2( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic2(uint32_t log_entry, uint32_t params...) {...} + */ +HOST_TRACE_EVENT_NTH_IMPL(2); - /* print trace event stderr*/ - if (strcmp(trace_class, "value") == 0) - fprintf - (stderr, - "Trace value %d, param1 %d param2 %d param3 %d\n", - event, param1, param2, param3); - else - fprintf(stderr, "Trace %s %c%c%c\n", trace_class, - c, b, a); - } +/* Implementation of + * void _trace_event3( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic3(uint32_t log_entry, uint32_t params...) {...} + */ +HOST_TRACE_EVENT_NTH_IMPL(3); - free(trace_class); -} +/* Implementation of + * void _trace_event4( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic4(uint32_t log_entry, uint32_t params...) {...} + */ +HOST_TRACE_EVENT_NTH_IMPL(4); -void _trace_event_mbox_atomic3(uint32_t event, uint32_t param1, - uint32_t param2, uint32_t param3) -{ - _trace_event3(event, param1, param2, param3); -} +/* Implementation of + * void _trace_event5( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic5(uint32_t log_entry, uint32_t params...) {...} + */ +HOST_TRACE_EVENT_NTH_IMPL(5); /* enable trace in testbench */ void tb_enable_trace(bool enable) diff --git a/src/include/sof/preproc-private-dec.h b/src/include/sof/preproc-private-dec.h new file mode 100644 index 000000000000..eda5eb02a747 --- /dev/null +++ b/src/include/sof/preproc-private-dec.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + + /* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */ + +#ifdef __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ +/* Macros defined in this file are only helpers for the macros that are + * defined in header file containing "namespace" + * __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ . + * This combination of #ifdef and #ifndef should sufficently narrow + * the "include-ability" of this dependent header file. + * If you wish to use macros from this file directly, be *V E R Y* careful! + * HIC SUNT DRACONES + */ +#ifndef __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE_DEC__ +#define __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE_DEC__ + +/* The only sane way I found to decrement values in cpreproc */ +/* for instance META_DEC(3) will be tokenized to DEC_3 + * and then expanded again to 2 + */ +#define _META_DEC_0 0 // notice how we deal with underflow +#define _META_DEC_1 0 +#define _META_DEC_2 1 +#define _META_DEC_3 2 +#define _META_DEC_4 3 +#define _META_DEC_5 4 +#define _META_DEC_6 5 +#define _META_DEC_7 6 +#define _META_DEC_8 7 +#define _META_DEC_9 8 +#define _META_DEC_10 9 +#define _META_DEC_11 10 +#define _META_DEC_12 11 +#define _META_DEC_13 12 +#define _META_DEC_14 13 +#define _META_DEC_15 14 +#define _META_DEC_16 15 +#define _META_DEC_17 16 +#define _META_DEC_18 17 +#define _META_DEC_19 18 +#define _META_DEC_20 19 +#define _META_DEC_21 20 +#define _META_DEC_22 21 +#define _META_DEC_23 22 +#define _META_DEC_24 23 +#define _META_DEC_25 24 +#define _META_DEC_26 25 +#define _META_DEC_27 26 +#define _META_DEC_28 27 +#define _META_DEC_29 28 +#define _META_DEC_30 29 +#define _META_DEC_31 30 +#define _META_DEC_32 31 +#define _META_DEC_33 32 +#define _META_DEC_34 33 +#define _META_DEC_35 34 +#define _META_DEC_36 35 +#define _META_DEC_37 36 +#define _META_DEC_38 37 +#define _META_DEC_39 38 +#define _META_DEC_40 39 +#define _META_DEC_41 40 +#define _META_DEC_42 41 +#define _META_DEC_43 42 +#define _META_DEC_44 43 +#define _META_DEC_45 44 +#define _META_DEC_46 45 +#define _META_DEC_47 46 +#define _META_DEC_48 47 +#define _META_DEC_49 48 +#define _META_DEC_50 49 +#define _META_DEC_51 50 +#define _META_DEC_52 51 +#define _META_DEC_53 52 +#define _META_DEC_54 53 +#define _META_DEC_55 54 +#define _META_DEC_56 55 +#define _META_DEC_57 56 +#define _META_DEC_58 57 +#define _META_DEC_59 58 +#define _META_DEC_60 59 +#define _META_DEC_61 60 +#define _META_DEC_62 61 +#define _META_DEC_63 62 +#define _META_DEC_64 63 + +#endif // __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE_DEC__ +#else + #error \ + Illegal use of header file: \ + can only be included from context of \ + __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ +#endif // __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ diff --git a/src/include/sof/preproc-private-inc.h b/src/include/sof/preproc-private-inc.h new file mode 100644 index 000000000000..8a11ab82080a --- /dev/null +++ b/src/include/sof/preproc-private-inc.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + + /* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */ + +#ifdef __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ +/* Macros defined in this file are only helpers for the macros that are + * defined in header file containing "namespace" + * __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ . + * This combination of #ifdef and #ifndef should sufficently narrow + * the "include-ability" of this dependent header file. + * If you wish to use macros from this file directly, be *V E R Y* careful! + * HIC SUNT DRACONES + */ +#ifndef __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE_INC__ +#define __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE_INC__ + +/* The only sane way I found to increment values in cpreproc */ +/* for instance META_INC(3) will be tokenized to INC_3 + * and then expanded again to 4 + */ +#define _META_INC_0 1 +#define _META_INC_1 2 +#define _META_INC_2 3 +#define _META_INC_3 4 +#define _META_INC_4 5 +#define _META_INC_5 6 +#define _META_INC_6 7 +#define _META_INC_7 8 +#define _META_INC_8 9 +#define _META_INC_9 10 +#define _META_INC_10 11 +#define _META_INC_11 12 +#define _META_INC_12 13 +#define _META_INC_13 14 +#define _META_INC_14 15 +#define _META_INC_15 16 +#define _META_INC_16 17 +#define _META_INC_17 18 +#define _META_INC_18 19 +#define _META_INC_19 20 +#define _META_INC_20 21 +#define _META_INC_21 22 +#define _META_INC_22 23 +#define _META_INC_23 24 +#define _META_INC_24 25 +#define _META_INC_25 26 +#define _META_INC_26 27 +#define _META_INC_27 28 +#define _META_INC_28 29 +#define _META_INC_29 30 +#define _META_INC_30 31 +#define _META_INC_31 32 +#define _META_INC_32 33 +#define _META_INC_33 34 +#define _META_INC_34 35 +#define _META_INC_35 36 +#define _META_INC_36 37 +#define _META_INC_37 38 +#define _META_INC_38 39 +#define _META_INC_39 40 +#define _META_INC_40 41 +#define _META_INC_41 42 +#define _META_INC_42 43 +#define _META_INC_43 44 +#define _META_INC_44 45 +#define _META_INC_45 46 +#define _META_INC_46 47 +#define _META_INC_47 48 +#define _META_INC_48 49 +#define _META_INC_49 50 +#define _META_INC_50 51 +#define _META_INC_51 52 +#define _META_INC_52 53 +#define _META_INC_53 54 +#define _META_INC_54 55 +#define _META_INC_55 56 +#define _META_INC_56 57 +#define _META_INC_57 58 +#define _META_INC_58 59 +#define _META_INC_59 60 +#define _META_INC_60 61 +#define _META_INC_61 62 +#define _META_INC_62 63 +#define _META_INC_63 64 +#define _META_INC_64 64 // notice how we deal with overflow + +#endif // __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE_INC__ +#else + #error \ + Illegal use of header file: \ + can only be included from context of \ + __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ +#endif // __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ diff --git a/src/include/sof/preproc-private.h b/src/include/sof/preproc-private.h new file mode 100644 index 000000000000..eae699cab6c8 --- /dev/null +++ b/src/include/sof/preproc-private.h @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + + /* THIS FILE SHOULD NOT BE INCLUDED DIRECTLY */ + +#ifdef __INCLUDE_MACRO_METAPROGRAMMING__ +/* Macros defined in this file are only helpers for the macros that are + * defined in header file containing "namespace" + * __INCLUDE_MACRO_METAPROGRAMMING__ . + * This combination of #ifdef and #ifndef should sufficently narrow + * the "include-ability" of this dependent header file. + * If you wish to use macros from this file directly, be *V E R Y* careful! + * HIC SUNT DRACONES + */ +#ifndef __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ +#define __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ + +/* Include + * #define _META_DEC_0 0 + * #define _META_DEC_1 1 + * #define _META_DEC_2 1 + * #define _META_DEC_3 2 + * ... + * #define _META_DEC_N N-1 + */ +#include +/* Include + * #define _META_INC_0 1 + * #define _META_INC_1 2 + * ... + * #define _META_INC_N-1 N + * #define _META_INC_N N + */ +#include + +/* count number of var args - during preprocesing + * works for predefined number of args + * META_COUNT_VARAGS_BEFORE_COMPILE(A,B,C,D) evaluates to 4 + */ +#define _META_PP_NARG_BEFORE_COMPILE_(...) \ + _META_PP_ARG_N(__VA_ARGS__) +#define _META_PP_ARG_N(\ + _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ + _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ + _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ + _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ + _61, _62, _63, N, ...) N + +#define _META_PP_RSEQ_N() \ + 63, 62, 61, 60, \ + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +/* treat x as string while forcing x expansion beforehand */ +#define _META_QUOTE(x) #x + +/* concat x and y while forcing x and y expansion beforehand */ +#define _META_CONCAT_BASE(x, y) x##y + +/* discard first x-1 args in vararg and return the xth arg */ +#define _META_GET_ARG_1(arg1, ...) arg1 +#define _META_GET_ARG_2(arg1, arg2, ...) arg2 +/* TODO: GET_ARG version for arbitrary x>2 should be possible using + * META_RECURSE(META_REPEAT + */ + +#define _META_NO_ARGS(...) 0 + +/* _META_IS_PROBE(...) evaluates to 0 when __VA_ARGS__ is single token + * _META_IS_PROBE(PROBE()) evaulates to 1, because it is equivalent to + * _META_GET_ARG_2(~, 1, 0) + * ~ is no special value, it is just a meaningless placeholder, + * it could be something else if that thing would also have no meaning + * but be a valid C + */ +#define _META_IS_PROBE(...) _META_GET_ARG_2(__VA_ARGS__, 0) +#define _META_PROBE() ~, 1 + +/* _META_NOT_0 evaluates to '~, 1' + * _META_NOT_1 evaluates to '_META_NOT_1' (because it is not a macro) + * _META_IS_PROBE(_META_NOT_0) evaluates to 1, because it is equivalent to + * _META_GET_ARG_2(~, 1, 0) + * _META_IS_PROBE(_NOT_1) evaluates to 0, because it is equivalent to + * _META_GET_ARG_2(_NOT_1, 0) + * + * notice, that any x!=0 would also result in 0 + * e.x. META_NOT(123) evaluates to 0 + */ +#define _META_NOT_0 _META_PROBE() + +/* indirection forces condition to be "cast" to 0 1 + * then for 0 discard first (), and for 1 discard second () + * so META_IF_ELSE(0)(a)(b) expands to b, + * and META_IF_ELSE(1)(a)(b) expands to a + */ +#define _META_IF_ELSE(condition) META_CONCAT(_META_IF_, condition) + +#define _META_IF_1(...) __VA_ARGS__ _META_IF_1_ELSE +#define _META_IF_0(...) _META_IF_0_ELSE + +#define _META_IF_1_ELSE(...) +#define _META_IF_0_ELSE(...) __VA_ARGS__ + +#define _META_IIF(condition) META_CONCAT(_META_IIF_, condition) +#define _META_IIF_0(x, ...) __VA_ARGS__ +#define _META_IIF_1(x, ...) x + +/* primitive recursion */ +#define _META_REQRS_1024(...) _META_REQRS_512(_META_REQRS_512(__VA_ARGS__)) +#define _META_REQRS_512(...) _META_REQRS_256(_META_REQRS_256(__VA_ARGS__)) +#define _META_REQRS_256(...) _META_REQRS_128(_META_REQRS_128(__VA_ARGS__)) +#define _META_REQRS_128(...) _META_REQRS_64( _META_REQRS_64 (__VA_ARGS__)) +#define _META_REQRS_64(...) _META_REQRS_32( _META_REQRS_32 (__VA_ARGS__)) +#define _META_REQRS_32(...) _META_REQRS_16( _META_REQRS_16 (__VA_ARGS__)) +#define _META_REQRS_16(...) _META_REQRS_8( _META_REQRS_8 (__VA_ARGS__)) +#define _META_REQRS_8(...) _META_REQRS_4( _META_REQRS_4 (__VA_ARGS__)) +#define _META_REQRS_4(...) _META_REQRS_2( _META_REQRS_2 (__VA_ARGS__)) +#define _META_REQRS_2(...) _META_REQRS_1( _META_REQRS_1 (__VA_ARGS__)) +#define _META_REQRS_1(...) __VA_ARGS__ + +/* Delay macro m expansion depth times + * IT IS CRUCIAL FOR NO #define _META_EMPTY macro to exist!!! + * _META_DEFER_N(depth) will work for any depth valid in META_REPEAT + * (which is confined only by META_DEC). + * _META_DEFER_N will NOT work inside META_REPEAT, because + * _META_DEFER_N uses META_REPEAT as seen below. + * In order for META_REPEAT to work (which also requires DEFER functionality) + * a duplicate, implicit _META_DEFER_2(m) has to be defined. + * It is because how the c preprocesor works. + */ +#define _META_EMPTY() + +/* These two will expand to: + * _META_EMPTY _META_EMPTY ... _META_EMPTY + * () () ... () + * Why '_META_EMPTY() _META_EMPTY' instead of '_META_EMPTY'? + * Using simply '_META_EMPTY' would produce + * _META_EMPTY_META_EMPTY_META_EMPTY + * and adding _META_EMPTY() introduces a " "(space) token. + */ +#define _META_EMPTY_GEN(i, rest) _META_EMPTY() _META_EMPTY +#define _META_PAREN_GEN(i, rest) () +/* You cannot use here META_RECURSE + * and must instead use _META_REQRS_{NUMBER}. + * If META_RECURSE was used, things like + * META_RECURSE(MAP_AGGREGATE +* would break. + */ +#define _META_DEFER_N(depth) \ + META_RECURSE_N(16, META_REPEAT(depth, _META_EMPTY_GEN, ~)) \ + META_RECURSE_N(16, META_REPEAT(depth, _META_PAREN_GEN, ~)) + +/* Special, implicit defer implementation for META_REPEAT to work */ +#define _META_DEFER_2(m) m _META_EMPTY _META_EMPTY () () + +/* helpers for consuming every single arg from __VA_ARGS__ */ +// expand and discard +#define _META_EAT(...) +// force expansion, reverse of META_DEFER +#define _META_EXPAND(...) __VA_ARGS__ +#define _META_WHEN(c) META_IF(c)(_META_EXPAND, _META_EAT) + +/* while(count--!=0) do + * uses DEC so count == N can only work if all following exist + * DEC_0, DEC_1, ..., DEC_N-1, DEC_N + */ +#define _META_REPEAT_INDIRECT() META_REPEAT + +/* map every group of arg_count arguments onto function m + * i.e. arg_count=2;m=ADD;args=1,2,3,4,5,6,7... + * results in ADD(1,2) ADD(3,4) ADD(5,6) and so on + * MAP##N must exist for arg_count == N to work + */ +#define _META_MAP() META_MAP + +/* implements MAP(1, m, ...) */ +#define _META_MAP_1(m, arg1, ...)\ + m(arg1)\ + _META_MAP_BODY(1, m, __VA_ARGS__) + +/* implements MAP(2, m, ...) */ +#define _META_MAP_2(m, arg1, arg2, ...)\ + m(arg1, arg2)\ + _META_MAP_BODY(2, m, __VA_ARGS__) + +/* implements MAP(3, m, ...) */ +#define _META_MAP_3(m, arg1, arg2, arg3, ...)\ + m(arg1, arg2, arg3)\ + _META_MAP_BODY(3, m, __VA_ARGS__) + +/* used by macro MAP, don't use on its own */ +#define _META_MAP_BODY(arg_count, m, ...)\ + META_IF_ELSE(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__))(\ + META_DEFER(2, _META_MAP)()\ + (arg_count, m, __VA_ARGS__)\ + )() + +/* map aggregator and every group of arg_count arguments onto function m + * i.e. aggr=x;arg_count=1;m=ADD;args=1,2,3,4,5,6,7... + * results in x = ... ADD(7,ADD(6,ADD(5,ADD(4,ADD(3,ADD(2,ADD(1,x))))))) ... + * MAP##N must exist for arg_count == N to work + */ +#define _META_MAP_AGGREGATE() META_MAP_AGGREGATE + +/* implements MAP_AGGREGATE(1, m, ...) */ +#define _META_MAP_AGGREGATE_1(m, aggr, arg1, ...)\ + _META_MAP_AGGREGATE_BODY(1, m, m(aggr, arg1), __VA_ARGS__) + +/* implements MAP_AGGREGATE(2, m, ...) */ +#define _META_MAP_AGGREGATE_2(m, aggr, arg1, arg2, ...)\ + _META_MAP_AGGREGATE_BODY(2, m, m(aggr, arg1, arg2), __VA_ARGS__) + +/* used by macro MAP_AGGREGATE, don't use on its own */ +#define _META_MAP_AGGREGATE_BODY(arg_count, m, aggr, ...)\ + META_IF_ELSE(META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__))(\ + META_DEFER(2, _META_MAP_AGGREGATE)()\ + (arg_count, m, aggr, __VA_ARGS__)\ + )(aggr) + +/* META_CONCAT with parametrised delimeter between concatenised tokens + * META_CONCAT_SEQ_DELIM_(A,B,C,D) tokenizes as A_B_C_D + */ +#define _META_CONCAT_DELIM(delim, x, y) META_CONCAT(META_CONCAT(x, delim),y) +#define _META_CONCAT_DELIM_(x, y) _META_CONCAT_DELIM(_, x, y) + +#endif // __INCLUDE_MACRO_METAPROGRAMMING_PRIVATE__ +#else + #error \ + Illegal use of header file: \ + can only be included from context of \ + __INCLUDE_MACRO_METAPROGRAMMING__ +#endif // __INCLUDE_MACRO_METAPROGRAMMING__ diff --git a/src/include/sof/preproc.h b/src/include/sof/preproc.h new file mode 100644 index 000000000000..8e6180e12494 --- /dev/null +++ b/src/include/sof/preproc.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#ifndef __INCLUDE_MACRO_METAPROGRAMMING__ +#define __INCLUDE_MACRO_METAPROGRAMMING__ + +/* Macros in this file are to be invoked directly from code. + * In order to work, they require a number of other macros that are + * defined in the header file specified below. + * Macros from the file specified below are not to meant to be used + * directly / independently. + * For more detailed commentary of innards of macros in this file, + * see file specified below. + */ +#include + +/* count number of var args - during preprocesing + * works for predefined number of args + * META_COUNT_VARAGS_BEFORE_COMPILE(A,B,C,D) evaluates to 4 + */ +#define META_COUNT_VARAGS_BEFORE_COMPILE(...)\ + META_IF_ELSE(META_HAS_ARGS(__VA_ARGS__)) (\ + _META_PP_NARG_BEFORE_COMPILE_(__VA_ARGS__, _META_PP_RSEQ_N())\ + )\ + (\ + 0\ + ) + +/* treat x as string while forcing x expansion beforehand */ +#define META_QUOTE(x) _META_QUOTE(x) + +/* concat x and y while forcing x and y expansion beforehand */ +#define META_CONCAT(x, y) _META_CONCAT_BASE(x, y) + +/* discard first x-1 args in vararg and return the xth arg */ + +#define META_GET_ARG_N(n, ...) META_CONCAT(_META_GET_ARG_, n)(__VA_ARGS__) + +#define META_HAS_ARGS(...) META_BOOL(\ + _META_GET_ARG_1(_META_NO_ARGS __VA_ARGS__)()\ +) + +/* Only META_NOT(0) evaulates to 1 + * notice, that any x!=0 would also result in 0 + * e.x. META_NOT(123) evaluates to 0 + */ +#define META_NOT(x) _META_IS_PROBE(META_CONCAT(_META_NOT_, x)) +/* hacky way to convert tokens into 0 1*/ +#define META_BOOL(x) META_NOT(META_NOT(x)) + +/* META_IF_ELSE(X)(a)(b) expands to + * b for X == 0 + * a for X != 0 + */ +#define META_IF_ELSE(condition) _META_IF_ELSE(META_BOOL(condition)) + +/* same story with indirection as META_IF_ELSE */ +#define META_IF(condition) _META_IIF(META_BOOL(condition)) + +/* primitive recursion + * default depth is 1024 + */ +#define META_RECURSE(...) _META_REQRS_1024(__VA_ARGS__) +/* choose explicitly depth of recursion + */ +#define META_RECURSE_N(depth, ...)\ + META_CONCAT(_META_REQRS_, depth)(__VA_ARGS__) + +/* The only sane way I found to increment values in cpreproc */ +#define META_INC(x) META_CONCAT(_META_INC_, x) + +/* The only sane way I found to decrement values in cpreproc */ +#define META_DEC(x) META_CONCAT(_META_DEC_, x) + +/* Delay macro m expansion depth times + * by writing META_DEFER(0, m)(args) we expand it in 1st scan + * by writing META_DEFER(1, m)(args) we expand it in 2nd scan + * ... + * by writing META_DEFER(n, m)(args) we expand it in n+1nth scan + */ +#define META_DEFER(depth, m) m _META_DEFER_N(depth) + +/* while(count--!=0) do + * uses DEC so count == N can only work if all following exist + * DEC_0, DEC_1, ..., DEC_N-1, DEC_N + */ +#define META_REPEAT(count, macro, ...)\ + _META_WHEN(count)\ + (\ + _META_DEFER_2(_META_REPEAT_INDIRECT) () \ + (META_DEC(count), macro, __VA_ARGS__)\ + _META_DEFER_2(macro)\ + (META_DEC(count), __VA_ARGS__)\ + ) + +/* map every group of arg_count arguments onto function m + * i.e. arg_count=2;m=ADD;args=1,2,3,4,5,6,7... + * results in ADD(1,2) ADD(3,4) ADD(5,6) and so on + * MAP##N must exist for arg_count == N to work + */ +#define META_MAP(arg_count, m, ...)\ + META_CONCAT(_META_MAP_, arg_count)(m, __VA_ARGS__) + +/* map aggregator and every group of arg_count arguments onto function m + * i.e. aggr=x;arg_count=1;m=ADD;args=1,2,3,4,5,6,7... + * results in x = ... ADD(7,ADD(6,ADD(5,ADD(4,ADD(3,ADD(2,ADD(1,x))))))) ... + * MAP##N must exist for arg_count == N to work + */ +#define META_MAP_AGGREGATE(arg_count, m, aggr, ...)\ + META_CONCAT(_META_MAP_AGGREGATE_, arg_count)(m, aggr, __VA_ARGS__) + +/* META_CONCAT_SEQ is basicaly variadic version of macro META_CONCAT + * META_CONCAT_SEQ(A,B,C,D) tokenizes to ABCD + */ +#define META_CONCAT_SEQ(aggr, ...) META_RECURSE(\ + META_MAP_AGGREGATE(1, META_CONCAT, aggr, __VA_ARGS__)) + +/* META_CONCAT with parametrised delimeter between concatenised tokens + * META_CONCAT_SEQ_DELIM_(A,B,C,D) tokenizes as A_B_C_D + */ +#define META_CONCAT_SEQ_DELIM_(aggr, ...) META_RECURSE(\ + META_MAP_AGGREGATE(1, _META_CONCAT_DELIM_, aggr, __VA_ARGS__)) + +/* META_SEQ_FROM_0_TO(3, META_SEQ_STEP_param) + * produces , param0 , param1 , param2 + */ +#define META_SEQ_FROM_0_TO(arg_count, func)\ + META_RECURSE(META_REPEAT(arg_count, func, ~)) + +/* Macros to be used as 2nd argument of macro META_SEQ_FROM_0_TO + * for instance + * META_SEQ_FROM_0_TO(arg_count, META_SEQ_STEP) + * produces + * 0 1 2 3 4 + */ +#define META_SEQ_STEP(i, _) i +#define META_SEQ_STEP_param(i, _) , META_CONCAT(param, i) +#define META_SEQ_STEP_param_uint32_t(i, _) , uint32_t META_CONCAT(param, i) +#define META_SEQ_STEP_param_uint64_t(i, _) , uint64_t META_CONCAT(param, i) +#define META_SEQ_STEP_param_int32_t( i, _) , int32_t META_CONCAT(param, i) +#define META_SEQ_STEP_param_int64_t( i, _) , int64_t META_CONCAT(param, i) + +/* generates function signature + * for instance with: + * prefix=foo ; postfix=__bar ; return_t=void + * fixed_args=(int x, int y) + * vararg_count=3 + * vararg_gen_step= + * #define META_SEQ_STEP_param_float(i, _) , float META_CONCAT(param, i) + * will produce: + * void foo_bar(int x, int y , float param0 , float param1 , float param2) + */ +#define META_FUNC_WITH_VARARGS(prefix, postfix, return_t,\ + fixed_args, vararg_count, vararg_gen_step)\ + return_t META_CONCAT_SEQ(prefix, postfix, vararg_count)\ + (fixed_args META_SEQ_FROM_0_TO(vararg_count, vararg_gen_step)) + +#endif // __INCLUDE_MACRO_METAPROGRAMMING__ diff --git a/src/include/sof/sof.h b/src/include/sof/sof.h index 4047420974c2..e94165540f27 100644 --- a/src/include/sof/sof.h +++ b/src/include/sof/sof.h @@ -34,6 +34,7 @@ #include #include #include +#include struct ipc; struct sa; @@ -51,8 +52,7 @@ struct sa; /* compile-time assertion */ #define STATIC_ASSERT(COND, MESSAGE) \ __attribute__((unused)) \ - typedef char assertion_failed_##MESSAGE[(COND) ? 1 : -1] - + typedef char META_CONCAT(assertion_failed_, MESSAGE)[(COND) ? 1 : -1] /* general firmware context */ struct sof { diff --git a/src/include/sof/trace.h b/src/include/sof/trace.h index 4ce04a8b9f4a..942226c6f662 100644 --- a/src/include/sof/trace.h +++ b/src/include/sof/trace.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -80,45 +81,99 @@ #define TRACE_BOOT_PLATFORM_DMIC (TRACE_BOOT_PLATFORM + 0x1a0) #define TRACE_BOOT_PLATFORM_IDC (TRACE_BOOT_PLATFORM + 0x1b0) +/* trace event classes - high 8 bits*/ +#define TRACE_CLASS_IRQ (1 << 24) +#define TRACE_CLASS_IPC (2 << 24) +#define TRACE_CLASS_PIPE (3 << 24) +#define TRACE_CLASS_HOST (4 << 24) +#define TRACE_CLASS_DAI (5 << 24) +#define TRACE_CLASS_DMA (6 << 24) +#define TRACE_CLASS_SSP (7 << 24) +#define TRACE_CLASS_COMP (8 << 24) +#define TRACE_CLASS_WAIT (9 << 24) +#define TRACE_CLASS_LOCK (10 << 24) +#define TRACE_CLASS_MEM (11 << 24) +#define TRACE_CLASS_MIXER (12 << 24) +#define TRACE_CLASS_BUFFER (13 << 24) +#define TRACE_CLASS_VOLUME (14 << 24) +#define TRACE_CLASS_SWITCH (15 << 24) +#define TRACE_CLASS_MUX (16 << 24) +#define TRACE_CLASS_SRC (17 << 24) +#define TRACE_CLASS_TONE (18 << 24) +#define TRACE_CLASS_EQ_FIR (19 << 24) +#define TRACE_CLASS_EQ_IIR (20 << 24) +#define TRACE_CLASS_SA (21 << 24) +#define TRACE_CLASS_DMIC (22 << 24) +#define TRACE_CLASS_POWER (23 << 24) +#define TRACE_CLASS_IDC (24 << 24) +#define TRACE_CLASS_CPU (25 << 24) + /* move to config.h */ #define TRACE 1 #define TRACEV 0 #define TRACEE 1 #define TRACEM 0 /* send all trace messages to mbox and local trace buffer */ -void _trace_event0(uint32_t log_entry); -void _trace_event_mbox0(uint32_t log_entry); -void _trace_event_atomic0(uint32_t log_entry); -void _trace_event_mbox_atomic0(uint32_t log_entry); - -void _trace_event1(uint32_t log_entry, uint32_t param); -void _trace_event_mbox1(uint32_t log_entry, uint32_t param); -void _trace_event_atomic1(uint32_t log_entry, uint32_t param); -void _trace_event_mbox_atomic1(uint32_t log_entry, uint32_t param); - -void _trace_event2(uint32_t log_entry, uint32_t param1, uint32_t param2); -void _trace_event_mbox2(uint32_t log_entry, uint32_t param1, uint32_t param2); -void _trace_event_atomic2(uint32_t log_entry, uint32_t param1, uint32_t param2); -void _trace_event_mbox_atomic2(uint32_t log_entry, uint32_t param1, - uint32_t param2); - -void _trace_event3(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3); -void _trace_event_mbox3(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3); -void _trace_event_atomic3(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3); -void _trace_event_mbox_atomic3(uint32_t log_entry, uint32_t param1, - uint32_t param2, uint32_t param3); - -void _trace_event4(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3, uint32_t param4); -void _trace_event_mbox4(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3, uint32_t param4); -void _trace_event_atomic4(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3, uint32_t param4); -void _trace_event_mbox_atomic4(uint32_t log_entry, uint32_t param1, - uint32_t param2, uint32_t param3, uint32_t param4); +#define _TRACE_EVENT_NTH(postfix, vararg_count)\ + META_FUNC_WITH_VARARGS(_trace_event, postfix, void,\ + META_CONCAT(, uint32_t log_entry),\ + vararg_count, META_SEQ_STEP_param_uint32_t) + +#define _TRACE_EVENT_NTH_DECLARE_GROUP(arg_count)\ + _TRACE_EVENT_NTH(, arg_count);\ + _TRACE_EVENT_NTH(_mbox, arg_count);\ + _TRACE_EVENT_NTH(_atomic, arg_count);\ + _TRACE_EVENT_NTH(_mbox_atomic, arg_count); + +/* Declaration of + * void _trace_event0 (uint32_t log_entry); + * void _trace_event_mbox0 (uint32_t log_entry); + * void _trace_event_atomic0 (uint32_t log_entry); + * void _trace_event_mbox_atomic0(uint32_t log_entry); + */ +_TRACE_EVENT_NTH_DECLARE_GROUP(0) + +/* Declaration of + * void _trace_event1 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox1 (uint32_t log_entry, uint32_t params...); + * void _trace_event_atomic1 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox_atomic1(uint32_t log_entry, uint32_t params...); + */ +_TRACE_EVENT_NTH_DECLARE_GROUP(1) + +/* Declaration of + * void _trace_event2 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox2 (uint32_t log_entry, uint32_t params...); + * void _trace_event_atomic2 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox_atomic2(uint32_t log_entry, uint32_t params...); + */ +_TRACE_EVENT_NTH_DECLARE_GROUP(2) + +/* Declaration of + * void _trace_event3 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox3 (uint32_t log_entry, uint32_t params...); + * void _trace_event_atomic3 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox_atomic3(uint32_t log_entry, uint32_t params...); + */ +_TRACE_EVENT_NTH_DECLARE_GROUP(3) + +/* Declaration of + * void _trace_event4 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox4 (uint32_t log_entry, uint32_t params...); + * void _trace_event_atomic4 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox_atomic4(uint32_t log_entry, uint32_t params...); + */ +_TRACE_EVENT_NTH_DECLARE_GROUP(4) + +/* Declaration of + * void _trace_event5 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox5 (uint32_t log_entry, uint32_t params...); + * void _trace_event_atomic5 (uint32_t log_entry, uint32_t params...); + * void _trace_event_mbox_atomic5(uint32_t log_entry, uint32_t params...); + */ +_TRACE_EVENT_NTH_DECLARE_GROUP(5) + +#define _TRACE_EVENT_MAX_ARGUMENT_COUNT 5 void trace_flush(void); void trace_off(void); @@ -133,9 +188,8 @@ void trace_init(struct sof *sof); * It comes in 2 main flavours, atomic and non-atomic. Depending of definitions * above, it might also propagate log messages to mbox if desired. * - * First argument is always class of event being logged, as defined in - * uapi/logging.h. - * Second argument is string literal in printf format, followed by up to 4 + * First argument is always class of event being logged, as defined above. + * Second argument is string literal in printf format, followed by up to 3 * parameters (uint32_t), that are used to expand into string fromat when * parsing log data. * @@ -227,28 +281,21 @@ typedef void(*log_func)(); format \ } -#define BASE_LOG(function_name, entry, ...) \ -{ \ - log_func log_function = NULL; \ - if (PP_NARG(__VA_ARGS__) == 0) { \ - log_function = (log_func)&function_name##0; \ - log_function(entry, ##__VA_ARGS__); \ - } else if (PP_NARG(__VA_ARGS__) == 1) { \ - log_function = (log_func)&function_name##1; \ - log_function(entry, ##__VA_ARGS__); \ - } else if (PP_NARG(__VA_ARGS__) == 2) { \ - log_function = (log_func)&function_name##2; \ - log_function(entry, ##__VA_ARGS__); \ - } else if (PP_NARG(__VA_ARGS__) == 3) { \ - log_function = (log_func)&function_name##3; \ - log_function(entry, ##__VA_ARGS__); \ - } else if (PP_NARG(__VA_ARGS__) == 4) { \ - log_function = (log_func)&function_name##4; \ - log_function(entry, ##__VA_ARGS__); \ - } else { \ - STATIC_ASSERT(PP_NARG(__VA_ARGS__) <= 4, \ - unsupported_amount_of_params_in_trace_event); \ - } \ +#define BASE_LOG_ASSERT_FAIL_MSG \ +unsupported_amount_of_params_in_trace_event\ +_thrown_from_macro_BASE_LOG_in_trace_h + +#define BASE_LOG(function_name, entry, ...)\ +{\ + STATIC_ASSERT(\ + _TRACE_EVENT_MAX_ARGUMENT_COUNT >=\ + META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__),\ + BASE_LOG_ASSERT_FAIL_MSG\ + );\ + log_func log_function = (log_func)&\ + META_CONCAT(function_name,\ + META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__));\ + log_function(entry, ##__VA_ARGS__);\ } #define __log_message(func_name, lvl, comp_id, format, ...) \ diff --git a/src/lib/trace.c b/src/lib/trace.c index c5efe988d317..85fa381c93ae 100644 --- a/src/lib/trace.c +++ b/src/lib/trace.c @@ -37,6 +37,7 @@ #include #include #include +#include #include struct trace { @@ -69,634 +70,140 @@ static void put_header(volatile uint32_t *dst, uint64_t timestamp) } } -/* send trace events only to the local trace buffer */ -void _trace_event0(uint32_t log_entry) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(0); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(0)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_atomic0(uint32_t log_entry) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(0); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(0)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events to the local trace buffer and the mailbox */ -void _trace_event_mbox0(uint32_t log_entry) -{ - unsigned long flags; - uint32_t message_size_dwords = MESSAGE_SIZE(0); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(0)]; - uint64_t time; - - volatile uint32_t *t; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - - dt[payload_offset] = log_entry; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); - - /* send event by mail box too. */ - spin_lock_irq(&trace->lock, flags); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - spin_unlock_irq(&trace->lock, flags); - - put_header(t, time); - t[payload_offset] = log_entry; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_mbox_atomic0(uint32_t log_entry) -{ - volatile uint32_t *t; - uint32_t message_size_dwords = MESSAGE_SIZE(0); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(0)]; - uint64_t time; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - dt[payload_offset] = log_entry; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - put_header(t, time); - t[payload_offset] = log_entry; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events only to the local trace buffer */ -void _trace_event1(uint32_t log_entry, uint32_t param) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(1); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(1)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_atomic1(uint32_t log_entry, uint32_t param) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(1); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(1)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events to the local trace buffer and the mailbox */ -void _trace_event_mbox1(uint32_t log_entry, uint32_t param) -{ - unsigned long flags; - uint32_t message_size_dwords = MESSAGE_SIZE(1); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(1)]; - uint64_t time; - - volatile uint32_t *t; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); - - /* send event by mail box too. */ - spin_lock_irq(&trace->lock, flags); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - spin_unlock_irq(&trace->lock, flags); - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_mbox_atomic1(uint32_t log_entry, uint32_t param) -{ - volatile uint32_t *t; - uint32_t message_size_dwords = MESSAGE_SIZE(1); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(1)]; - uint64_t time; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events only to the local trace buffer */ -void _trace_event2(uint32_t log_entry, uint32_t param1, uint32_t param2) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(2); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(2)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_atomic2(uint32_t log_entry, uint32_t param1, uint32_t param2) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(2); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(2)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events to the local trace buffer and the mailbox */ -void _trace_event_mbox2(uint32_t log_entry, uint32_t param1, uint32_t param2) -{ - unsigned long flags; - uint32_t message_size_dwords = MESSAGE_SIZE(2); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(2)]; - uint64_t time; - - volatile uint32_t *t; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); - - /* send event by mail box too. */ - spin_lock_irq(&trace->lock, flags); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - spin_unlock_irq(&trace->lock, flags); - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param1; - t[payload_offset + 2] = param2; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_mbox_atomic2(uint32_t log_entry, uint32_t param1, - uint32_t param2) -{ - volatile uint32_t *t; - uint32_t message_size_dwords = MESSAGE_SIZE(2); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(2)]; - uint64_t time; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param1; - t[payload_offset + 2] = param2; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events only to the local trace buffer */ -void _trace_event3(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(3); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(3)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_atomic3(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(3); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(3)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events to the local trace buffer and the mailbox */ -void _trace_event_mbox3(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3) -{ - unsigned long flags; - uint32_t message_size_dwords = MESSAGE_SIZE(3); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(3)]; - uint64_t time; - - volatile uint32_t *t; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); - - /* send event by mail box too. */ - spin_lock_irq(&trace->lock, flags); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - spin_unlock_irq(&trace->lock, flags); - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param1; - t[payload_offset + 2] = param2; - t[payload_offset + 3] = param3; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_mbox_atomic3(uint32_t log_entry, uint32_t param1, - uint32_t param2, uint32_t param3) -{ - volatile uint32_t *t; - uint32_t message_size_dwords = MESSAGE_SIZE(3); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(3)]; - uint64_t time; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param1; - t[payload_offset + 2] = param2; - t[payload_offset + 3] = param3; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events only to the local trace buffer */ -void _trace_event4(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3, uint32_t param4) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(4); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(4)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dt[payload_offset + 4] = param4; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_atomic4(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3, uint32_t param4) -{ - uint32_t message_size_dwords = MESSAGE_SIZE(4); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(4)]; - - if (!trace->enable) - return; - - put_header(dt, platform_timer_get(platform_timer)); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dt[payload_offset + 4] = param4; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); -} - -/* send trace events to the local trace buffer and the mailbox */ -void _trace_event_mbox4(uint32_t log_entry, uint32_t param1, uint32_t param2, - uint32_t param3, uint32_t param4) -{ - unsigned long flags; - uint32_t message_size_dwords = MESSAGE_SIZE(4); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(4)]; - uint64_t time; - - volatile uint32_t *t; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); - - put_header(dt, time); - - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dt[payload_offset + 4] = param4; - dtrace_event((const char *)dt, sizeof(uint32_t) * message_size_dwords); - - /* send event by mail box too. */ - spin_lock_irq(&trace->lock, flags); - - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; - - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; - - spin_unlock_irq(&trace->lock, flags); - - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param1; - t[payload_offset + 2] = param2; - t[payload_offset + 3] = param3; - t[payload_offset + 4] = param4; - - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} - -void _trace_event_mbox_atomic4(uint32_t log_entry, uint32_t param1, - uint32_t param2, uint32_t param3, uint32_t param4) -{ - volatile uint32_t *t; - uint32_t message_size_dwords = MESSAGE_SIZE(4); - uint32_t payload_offset = sizeof(struct log_entry_header) - / sizeof(uint32_t); - uint32_t dt[MESSAGE_SIZE(4)]; - uint64_t time; - - if (!trace->enable) - return; - - time = platform_timer_get(platform_timer); +/* TODO: it should be possible to do this for arbitrary array, passed as an arg + * something like: + * #define FOO(array, i, _) array[payload_offset + 1 + i] =\ + * META_CONCAT(param, i); + * #define BAR(array, arg_count) META_SEQ_FROM_0_TO(arg_count, FOO(array)) + */ +#define _TRACE_EVENT_NTH_IMPL_DT_STEP(i, _)\ + dt[payload_offset + 1 + i] = META_CONCAT(param, i); +#define _TRACE_EVENT_NTH_IMPL_T_STEP(i, _)\ + t[payload_offset + 1 + i] = META_CONCAT(param, i); +#define _TRACE_EVENT_NTH_IMPL_DT(arg_count)\ + META_SEQ_FROM_0_TO(arg_count, _TRACE_EVENT_NTH_IMPL_DT_STEP) +#define _TRACE_EVENT_NTH_IMPL_T(arg_count)\ + META_SEQ_FROM_0_TO(arg_count, _TRACE_EVENT_NTH_IMPL_T_STEP) + +/* _trace_event function with poor people's version of constexpr if */ +#define _TRACE_EVENT_NTH_IMPL(is_mbox, is_atomic, arg_count)\ +_TRACE_EVENT_NTH(META_CONCAT(\ +/*if is_mbox , append _mbox to function name*/\ +META_IF_ELSE(is_mbox)(_mbox)(),\ +/*if is_atomic, append _atomic to function name*/\ +META_IF_ELSE(is_atomic)(_atomic)()\ +), arg_count)\ +{\ + const uint32_t msg_size_dwords = MESSAGE_SIZE(arg_count);\ + const uint32_t payload_offset = sizeof(struct log_entry_header)\ + / sizeof(uint32_t);\ + uint32_t dt[MESSAGE_SIZE(arg_count)];\ + META_IF_ELSE(is_mbox)\ + (\ + volatile uint32_t *t;\ + META_IF_ELSE(is_atomic)()(unsigned long flags;)\ + )()\ +\ + if (!trace->enable)\ + return;\ +\ + META_IF_ELSE(is_mbox)\ + (\ + uint64_t time = platform_timer_get(platform_timer);\ + put_header(dt, time);\ + )\ + (\ + put_header(dt, platform_timer_get(platform_timer));\ + )\ +\ + dt[payload_offset] = log_entry;\ + _TRACE_EVENT_NTH_IMPL_DT(arg_count)\ + META_IF_ELSE(is_atomic)\ + (dtrace_event_atomic)\ + (dtrace_event)\ + ((const char *)dt, sizeof(uint32_t) * msg_size_dwords);\ + META_IF_ELSE(is_mbox)\ + (\ + META_IF_ELSE(is_atomic)()(\ + /* send event by mail box too. */\ + spin_lock_irq(&trace->lock, flags);\ + )\ + /* write timestamp and event to trace buffer */\ + t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos);\ + trace->pos += sizeof(uint32_t) * msg_size_dwords;\ +\ + if (trace->pos > MAILBOX_TRACE_SIZE\ + - sizeof(uint32_t) * msg_size_dwords)\ + trace->pos = 0;\ +\ + META_IF_ELSE(is_atomic)()(spin_unlock_irq(&trace->lock, flags);)\ +\ + put_header(t, time);\ + t[payload_offset] = log_entry;\ + _TRACE_EVENT_NTH_IMPL_T(arg_count)\ +\ + /* writeback trace data */\ + dcache_writeback_region\ + ((void *)t, sizeof(uint32_t) * msg_size_dwords);\ + )()\ +} + +#define _TRACE_EVENT_NTH_IMPL_GROUP(arg_count)\ + /* send trace events only to the local trace buffer */\ + _TRACE_EVENT_NTH_IMPL(0, 0, arg_count)\ + _TRACE_EVENT_NTH_IMPL(0, 1, arg_count)\ + /* send trace events to the local trace buffer and the mailbox */\ + _TRACE_EVENT_NTH_IMPL(1, 0, arg_count)\ + _TRACE_EVENT_NTH_IMPL(1, 1, arg_count) + + +/* Implementation of + * void _trace_event1( uint32_t log_entry) {...} + * void _trace_event_mbox1( uint32_t log_entry) {...} + * void _trace_event_atomic1( uint32_t log_entry) {...} + * void _trace_event_mbox_atomic1(uint32_t log_entry) {...} + */ +_TRACE_EVENT_NTH_IMPL_GROUP(0) - put_header(dt, time); - dt[payload_offset] = log_entry; - dt[payload_offset + 1] = param1; - dt[payload_offset + 2] = param2; - dt[payload_offset + 3] = param3; - dt[payload_offset + 4] = param4; - dtrace_event_atomic((const char *)dt, - sizeof(uint32_t) * message_size_dwords); +/* Implementation of + * void _trace_event1( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox1( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_atomic1( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic1(uint32_t log_entry, uint32_t params...) {...} + */ +_TRACE_EVENT_NTH_IMPL_GROUP(1) - /* write timestamp and event to trace buffer */ - t = (volatile uint32_t *)(MAILBOX_TRACE_BASE + trace->pos); - trace->pos += sizeof(uint32_t) * message_size_dwords; +/* Implementation of + * void _trace_event2( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox2( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_atomic2( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic2(uint32_t log_entry, uint32_t params...) {...} + */ +_TRACE_EVENT_NTH_IMPL_GROUP(2) - if (trace->pos > MAILBOX_TRACE_SIZE - - sizeof(uint32_t) * message_size_dwords) - trace->pos = 0; +/* Implementation of + * void _trace_event3( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox3( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_atomic3( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic3(uint32_t log_entry, uint32_t params...) {...} + */ +_TRACE_EVENT_NTH_IMPL_GROUP(3) - put_header(t, time); - t[payload_offset] = log_entry; - t[payload_offset + 1] = param1; - t[payload_offset + 2] = param2; - t[payload_offset + 3] = param3; - t[payload_offset + 4] = param4; +/* Implementation of + * void _trace_event4( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox4( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_atomic4( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic4(uint32_t log_entry, uint32_t params...) {...} + */ +_TRACE_EVENT_NTH_IMPL_GROUP(4) - /* writeback trace data */ - dcache_writeback_region((void *)t, - sizeof(uint32_t) * message_size_dwords); -} +/* Implementation of + * void _trace_event5( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox5( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_atomic5( uint32_t log_entry, uint32_t params...) {...} + * void _trace_event_mbox_atomic5(uint32_t log_entry, uint32_t params...) {...} + */ +_TRACE_EVENT_NTH_IMPL_GROUP(5) void trace_flush(void) { diff --git a/test/cmocka/Makefile.am b/test/cmocka/Makefile.am index 8bbda87b8629..682515c64687 100644 --- a/test/cmocka/Makefile.am +++ b/test/cmocka/Makefile.am @@ -83,6 +83,33 @@ pipeline_free_SOURCES = ../../src/audio/pipeline.c src/audio/pipeline/pipeline_m endif +# lib/preproc tests + +check_PROGRAMS += preproc_varargs_count +preproc_varargs_count_SOURCES =\ + src/lib/preproc/varargs_count.c + +check_PROGRAMS += preproc_concat +preproc_concat_SOURCES =\ + src/lib/preproc/concat.c + +check_PROGRAMS += preproc_seq +preproc_seq_SOURCES =\ + src/lib/preproc/seq.c + +check_PROGRAMS += preproc_defer +preproc_defer_SOURCES =\ + src/lib/preproc/defer.c + +check_PROGRAMS += preproc_get_arg +preproc_get_arg_SOURCES =\ + src/lib/preproc/get_arg.c + +# debugability tests + +check_PROGRAMS += debugability_macros +debugability_macros_SOURCES = src/debugability/macros.c + # lib/lib tests check_PROGRAMS += rstrcmp diff --git a/test/cmocka/include/test_group_generator.h b/test/cmocka/include/test_group_generator.h index b3701eaa92ba..005019fdf0c7 100644 --- a/test/cmocka/include/test_group_generator.h +++ b/test/cmocka/include/test_group_generator.h @@ -1,3 +1,8 @@ +#include +#include +#include +#include + /* CMOCKA SETUP */ #define setup_alloc(ptr, type, size, offset) do {\ if (ptr)\ @@ -15,31 +20,12 @@ /* TEST GROUPS GENERATORS */ -#define ESCAPE_TOKEN(NAME, x, y) NAME(x, y) -// get specialisation for given number of args for a variadic macro -#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME - -#define BASE_CONCAT(x, y) x ## _ ## y // pattern of concatenisation -// pseudo variadic token concat -#define CONCAT(...) GET_MACRO(__VA_ARGS__, \ -CONCAT9, CONCAT8, CONCAT7, CONCAT6, CONCAT5, \ -CONCAT4, CONCAT3, CONCAT2, CONCAT1)(__VA_ARGS__) -#define CONCAT1(f1) f1 -#define CONCAT2(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT1(__VA_ARGS__)) -#define CONCAT3(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT2(__VA_ARGS__)) -#define CONCAT4(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT3(__VA_ARGS__)) -#define CONCAT5(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT4(__VA_ARGS__)) -#define CONCAT6(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT5(__VA_ARGS__)) -#define CONCAT7(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT6(__VA_ARGS__)) -#define CONCAT8(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT7(__VA_ARGS__)) -#define CONCAT9(f1, ...) ESCAPE_TOKEN(BASE_CONCAT, f1, CONCAT8(__VA_ARGS__)) - -#define gen_test_concat(prefix, name) CONCAT(prefix, name) -#define gen_test_concat_base(prefix) CONCAT(prefix, base) +#define gen_test_concat(prefix, name) META_CONCAT_SEQ_DELIM_(prefix, name) +#define gen_test_concat_base(prefix) META_CONCAT_SEQ_DELIM_(prefix, base) #define gen_test_concat_func(prefix, name, ...) \ -CONCAT(prefix, name, for, __VA_ARGS__) +META_CONCAT_SEQ_DELIM_(prefix, name, for, __VA_ARGS__) #define gen_test_concat_flag(prefix, ...) \ -CONCAT(prefix, isetup, for, __VA_ARGS__) +META_CONCAT_SEQ_DELIM_(prefix, isetup, for, __VA_ARGS__) // make function body for "${prefix}_${name}_for_${dlen}_${cbeg}_${cend}" #define gen_test_with_prefix(prefix_check, prefix_setup, name, ...) \ @@ -54,7 +40,6 @@ static void gen_test_concat_func(prefix_setup, name, __VA_ARGS__) \ gen_test_concat(prefix_check, name)(state);\ } -#define c_u_t(x) cmocka_unit_test(x) #define c_u_t_concat(prefix_check, prefix_setup, name, ...)\ c_u_t(gen_test_concat_func(prefix_setup, name, __VA_ARGS__)), diff --git a/test/cmocka/include/test_simple_macro.h b/test/cmocka/include/test_simple_macro.h new file mode 100644 index 000000000000..b44e5833143a --- /dev/null +++ b/test/cmocka/include/test_simple_macro.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#define c_u_t(x) cmocka_unit_test(x) + +#define TEST_HERE_DECLARE(test_func, ...)\ + TEST_FUNC(TEST_PREFIX, test_func, __VA_ARGS__) + +#define TEST_HERE_USE(test_func, postfix)\ + c_u_t(META_CONCAT_SEQ_DELIM_(TEST_PREFIX, test_func, postfix)) diff --git a/test/cmocka/src/debugability/macros.c b/test/cmocka/src/debugability/macros.c new file mode 100644 index 000000000000..dcda299225f5 --- /dev/null +++ b/test/cmocka/src/debugability/macros.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define CAPTURE(aggr, ...)\ + META_RECURSE(META_MAP(1, META_QUOTE, aggr, __VA_ARGS__)) + +static void test_debugability_macros_declare_log_entry(void **state) +{ + const char *macro_result = CAPTURE(_DECLARE_LOG_ENTRY( + LOG_LEVEL_CRITICAL, "Message", TRACE_CLASS_DMA, 1)); + const char *should_be_eq = + "__attribute__((section(\".static_log.\"" + " \"LOG_LEVEL_CRITICAL\"))) " + "static const struct { uint32_t level; uint32_t component_id; " + "uint32_t params_num; uint32_t line_idx; uint32_t file_name_len; " + "const char file_name[sizeof(\"src/debugability/macros.c\")]; " + "uint32_t text_len; const char text[sizeof(\"Message\")]; } " + "log_entry = { 1"; + (void)state; + + assert_string_equal(macro_result, should_be_eq); +} + +static char *get_param_list(const int param_count) +{ + char *result = malloc(sizeof(char) * 128); + int current; + + strcpy(result, ""); + for (current = 0; current < param_count; ++current) { + char newparam[11]; + + sprintf(newparam, ", param%d", current); + strcat(result, newparam); + } + return result; +} + +static char *get_should_be(const int param_count) +{ + char *result = malloc(sizeof(char) * 1024); + char *paramlist = get_param_list(param_count); + char *maybe_space = " "; + char *maybe_comma = ","; + + if (!param_count) + maybe_space = ""; + else + maybe_comma = ""; + + /* which format: 0 1 2 3 4 5 6 7 8 9 A*/ + sprintf(result, "%s%d%s%d%s%s%d%s%s%s%s", + /*0*/"{ __attribute__((unused)) typedef char assertion_failed_" + META_QUOTE(BASE_LOG_ASSERT_FAIL_MSG) + "[(", + /*1*/_TRACE_EVENT_MAX_ARGUMENT_COUNT, + /*2*/" >= ", + /*3*/param_count, + /*4*/maybe_space, + /*5*/") ? 1 : -1]; log_func log_function = (log_func)& _trace_event", + /*6*/param_count, + /*7*/"; log_function(&log_entry", + /*8*/maybe_comma, + /*9*/paramlist, + /*A*/");}" + ); + if (paramlist) + free(paramlist); + return result; +} + +#define test_debugability_macros_base_base(...)\ +do {\ + _DECLARE_LOG_ENTRY(\ + LOG_LEVEL_CRITICAL,\ + "Message",\ + TRACE_CLASS_DMA,\ + META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__)\ + );\ + const char *macro_result = CAPTURE(BASE_LOG(\ + _trace_event,\ + &log_entry,\ + __VA_ARGS__\ + ));\ + char *should_be_eq = get_should_be(\ + META_COUNT_VARAGS_BEFORE_COMPILE(__VA_ARGS__));\ +\ + /* to avoid "log_entry not used" warning */\ + assert_true(log_entry.level == log_entry.level);\ +\ + (void)state;\ +\ + assert_string_equal(macro_result, should_be_eq);\ + if (should_be_eq)\ + free(should_be_eq);\ +} while (0)\ + +#define TEST_FUNC_(param_count, ...)\ +static void META_CONCAT_SEQ_DELIM_(\ + test_debugability_macros_base_log,\ + param_count,\ + params)\ +(void **state)\ +{\ + test_debugability_macros_base_base(__VA_ARGS__);\ +} + +TEST_FUNC_(0,) +TEST_FUNC_(1, param0) +TEST_FUNC_(2, param0, param1) +TEST_FUNC_(3, param0, param1, param2) +TEST_FUNC_(4, param0, param1, param2, param3) +TEST_FUNC_(5, param0, param1, param2, param3, param4) +#undef TEST_FUNC_ +#undef CAPTURE + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_debugability_macros_declare_log_entry), + cmocka_unit_test(test_debugability_macros_base_log_0_params), + cmocka_unit_test(test_debugability_macros_base_log_1_params), + cmocka_unit_test(test_debugability_macros_base_log_2_params), + cmocka_unit_test(test_debugability_macros_base_log_3_params), + cmocka_unit_test(test_debugability_macros_base_log_4_params), + cmocka_unit_test(test_debugability_macros_base_log_5_params), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} + diff --git a/test/cmocka/src/lib/preproc/concat.c b/test/cmocka/src/lib/preproc/concat.c new file mode 100644 index 000000000000..e6be1f3ea402 --- /dev/null +++ b/test/cmocka/src/lib/preproc/concat.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#define TEST_PREFIX test_lib_preproc + +#define TEST_FUNC(prefix, test_func, postfix, should_be, ...)\ +static void META_CONCAT_SEQ_DELIM_(prefix, test_func, postfix)(void **state)\ +{\ + const int r = test_func(__VA_ARGS__);\ + (void)state;\ +\ + assert_int_equal(r, should_be);\ +} +#define A 1 +#define B 2 +#define C 3 + +TEST_HERE_DECLARE(META_CONCAT, 1_nothing, 1, A, ) +TEST_HERE_DECLARE(META_CONCAT, nothing_2, 2, , B ) +TEST_HERE_DECLARE(META_CONCAT, 1_2, 12, A, B ) +TEST_HERE_DECLARE(META_CONCAT_SEQ, 1_nothing, 1, A, ) +TEST_HERE_DECLARE(META_CONCAT_SEQ, nothing_2, 2, , B ) +TEST_HERE_DECLARE(META_CONCAT_SEQ, 1_2, 12, A, B ) +TEST_HERE_DECLARE(META_CONCAT_SEQ, 1_2_3, 123, A, B, C) + +#undef C +#undef B +#undef A +#undef TEST_FUNC + +int main(void) +{ + const struct CMUnitTest tests[] = { + TEST_HERE_USE(META_CONCAT, 1_nothing), + TEST_HERE_USE(META_CONCAT, nothing_2), + TEST_HERE_USE(META_CONCAT, 1_2 ), + + TEST_HERE_USE(META_CONCAT_SEQ, 1_nothing), + TEST_HERE_USE(META_CONCAT_SEQ, nothing_2), + TEST_HERE_USE(META_CONCAT_SEQ, 1_2 ), + TEST_HERE_USE(META_CONCAT_SEQ, 1_2_3 ), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} + +#undef TEST_PREFIX diff --git a/test/cmocka/src/lib/preproc/defer.c b/test/cmocka/src/lib/preproc/defer.c new file mode 100644 index 000000000000..205ba5c26bb1 --- /dev/null +++ b/test/cmocka/src/lib/preproc/defer.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#define TEST_PREFIX test_lib_preproc + +#define TEST_FUNC(prefix, test_func, postfix, should_be, ...)\ +static void META_CONCAT_SEQ_DELIM_(prefix, test_func, postfix)(void **state)\ +{\ + const char *r = META_QUOTE(test_func(__VA_ARGS__));\ + (void)state;\ +\ + assert_string_equal(r, should_be);\ +} +#define TEST() FINAL + +TEST_HERE_DECLARE(META_DEFER, 0,\ + "TEST"\ + , 0, TEST) +TEST_HERE_DECLARE(META_DEFER, 1,\ + "TEST _META_EMPTY"\ + " ()"\ + , 1, TEST) +TEST_HERE_DECLARE(META_DEFER, 2,\ + "TEST _META_EMPTY _META_EMPTY"\ + " () ()"\ + , 2, TEST) +TEST_HERE_DECLARE(META_DEFER, 3,\ + "TEST _META_EMPTY _META_EMPTY _META_EMPTY"\ + " () () ()"\ + , 3, TEST) +TEST_HERE_DECLARE(META_DEFER, 4,\ + "TEST _META_EMPTY _META_EMPTY _META_EMPTY _META_EMPTY"\ + " () () () ()"\ + , 4, TEST) +TEST_HERE_DECLARE(META_DEFER, 5,\ + "TEST _META_EMPTY _META_EMPTY _META_EMPTY _META_EMPTY _META_EMPTY"\ + " () () () () ()"\ + , 5, TEST) + +#undef TEST +#undef TEST_FUNC + +int main(void) +{ + const struct CMUnitTest tests[] = { + TEST_HERE_USE(META_DEFER, 0), + TEST_HERE_USE(META_DEFER, 1), + TEST_HERE_USE(META_DEFER, 2), + TEST_HERE_USE(META_DEFER, 3), + TEST_HERE_USE(META_DEFER, 4), + TEST_HERE_USE(META_DEFER, 5), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} + +#undef TEST_PREFIX diff --git a/test/cmocka/src/lib/preproc/get_arg.c b/test/cmocka/src/lib/preproc/get_arg.c new file mode 100644 index 000000000000..3e6bae417cdf --- /dev/null +++ b/test/cmocka/src/lib/preproc/get_arg.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#include + +#include +#include +#include + +#include +#include + +static void test_lib_preproc_get_arg_1(void **state) +{ + const char* what_we_get = _META_GET_ARG_1("a", "B", "c", "D", "e"); + const char* what_we_should_get = "a"; + + (void)state; + + assert_string_equal(what_we_get, what_we_should_get); +} + +static void test_lib_preproc_get_arg_2(void **state) +{ + const char* what_we_get = _META_GET_ARG_2("a", "B", "c", "D", "e"); + const char* what_we_should_get = "B"; + + (void)state; + + assert_string_equal(what_we_get, what_we_should_get); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_lib_preproc_get_arg_1), + cmocka_unit_test(test_lib_preproc_get_arg_2), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/src/lib/preproc/seq.c b/test/cmocka/src/lib/preproc/seq.c new file mode 100644 index 000000000000..56caa7639dfb --- /dev/null +++ b/test/cmocka/src/lib/preproc/seq.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ +#include + +#include +#include +#include +#include + +#include +#include + +#define TEST_PREFIX test_lib_preproc + +#define TEST_FUNC(prefix, test_func, postfix, should_be, ...)\ +static void META_CONCAT_SEQ_DELIM_(prefix, test_func, postfix)(void **state)\ +{\ + const char* r = META_QUOTE(test_func(__VA_ARGS__));\ + (void)state;\ +\ + assert_string_equal(r, should_be);\ +} + +TEST_HERE_DECLARE(META_SEQ_FROM_0_TO, int_0, "", 0, META_SEQ_STEP) +TEST_HERE_DECLARE(META_SEQ_FROM_0_TO, int_1, "0", 1, META_SEQ_STEP) +TEST_HERE_DECLARE(META_SEQ_FROM_0_TO, int_3, "0 1 2", 3, META_SEQ_STEP) + +#undef TEST_FUNC + +#define CAPTURE_PARAMS_PART(x, y) x " , " META_QUOTE(y) +#define CAPTURE_PARAMS(aggr, ...) META_RECURSE(\ + META_MAP_AGGREGATE(1, CAPTURE_PARAMS_PART, aggr, __VA_ARGS__)) + +#define TEST_FUNC(prefix, test_func, postfix, should_be, ...)\ +static void META_CONCAT_SEQ_DELIM_(prefix, test_func, postfix)(void **state)\ +{\ + const char *r = CAPTURE_PARAMS(test_func(__VA_ARGS__));\ + (void)state;\ +\ + assert_string_equal(r, " , " should_be);\ +} + +TEST_HERE_DECLARE(META_SEQ_FROM_0_TO, param_0,\ + "",\ + 0, META_SEQ_STEP_param_uint32_t) +TEST_HERE_DECLARE(META_SEQ_FROM_0_TO, param_1,\ + "uint32_t param0",\ + 1, META_SEQ_STEP_param_uint32_t) +TEST_HERE_DECLARE(META_SEQ_FROM_0_TO, param_3,\ + "uint32_t param0 , uint32_t param1 , uint32_t param2",\ + 3, META_SEQ_STEP_param_uint32_t) + +#undef TEST_FUNC +#undef CAPTURE_PARAMS +#undef CAPTURE_PARAMS_PART + +int main(void) +{ + const struct CMUnitTest tests[] = { + TEST_HERE_USE(META_SEQ_FROM_0_TO, int_0), + TEST_HERE_USE(META_SEQ_FROM_0_TO, int_1), + TEST_HERE_USE(META_SEQ_FROM_0_TO, int_3), + + TEST_HERE_USE(META_SEQ_FROM_0_TO, param_0), + TEST_HERE_USE(META_SEQ_FROM_0_TO, param_1), + TEST_HERE_USE(META_SEQ_FROM_0_TO, param_3), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} + +#undef TEST_PREFIX diff --git a/test/cmocka/src/lib/preproc/varargs_count.c b/test/cmocka/src/lib/preproc/varargs_count.c new file mode 100644 index 000000000000..b67983b2e1c0 --- /dev/null +++ b/test/cmocka/src/lib/preproc/varargs_count.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Michal Jerzy Wierzbicki + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#define TEST_PREFIX test_lib_preproc + +#define TEST_FUNC(prefix, test_func, postfix, should_be, ...)\ +static void META_CONCAT_SEQ_DELIM_(prefix, test_func, postfix)(void **state)\ +{\ + const int r = test_func(__VA_ARGS__);\ + (void)state;\ +\ + assert_int_equal(r, should_be);\ +} +#define A 1 +#define B 2 +#define C 3 + +#define META_NAME META_COUNT_VARAGS_BEFORE_COMPILE +TEST_HERE_DECLARE(META_NAME, 0, 0, ) +TEST_HERE_DECLARE(META_NAME, 1, 1, A ) +TEST_HERE_DECLARE(META_NAME, 3, 3, A, B, C) +TEST_HERE_DECLARE(PP_NARG , 0, 0, ) +TEST_HERE_DECLARE(PP_NARG , 1, 1, A ) +TEST_HERE_DECLARE(PP_NARG , 3, 3, A, B, C) + +#undef C +#undef B +#undef A +#undef TEST_FUNC + +int main(void) +{ + const struct CMUnitTest tests[] = { + TEST_HERE_USE(META_NAME, 0), + TEST_HERE_USE(META_NAME, 1), + TEST_HERE_USE(META_NAME, 3), + TEST_HERE_USE(PP_NARG , 0), + TEST_HERE_USE(PP_NARG , 1), + TEST_HERE_USE(PP_NARG , 3), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} + +#undef META_NAME +#undef TEST_PREFIX