diff --git a/doc/draft_g191.docx b/doc/draft_g191.docx new file mode 100644 index 0000000..9015f4c Binary files /dev/null and b/doc/draft_g191.docx differ diff --git a/doc/g191.md b/doc/g191.md index 0feabbb..58cab3b 100644 --- a/doc/g191.md +++ b/doc/g191.md @@ -12,17 +12,31 @@ Please refer to the official Recommendation ITU-T G.191 for the complete text: [ Recommendation ITU-T G.191 provides source code for speech and audio processing modules for narrowband, wideband and super-wideband telephony applications. The set includes codecs, filters, noise generators. -This edition introduces changes to Annex A, which describes the ITU-T Software Tools (STL) containing a high-quality, portable C code library for speech processing applications. This release of the STL, also known as STL2023, incorporates: +This edition introduces changes to Annex A, which describes the ITU-T Software Tools (STL) containing a high-quality, portable C code library for speech processing applications. This release of the STL, also known as STL2024, incorporates: -* An implementation of P.50 fullband MNRU as described in ITU-T P.810. +* BS1770demo improvements: -* A tool for automatic instrumentation of speech and audio codecs to measure their computational complexity and memory. + - a new RMS option disabling the gating function for background noise measurement, -Recommendation ITU-T G.191 includes an electronic attachment containing STL2023 and manual. + - the handling of the edge case where all gating blacks are below -70 LKFS, + + - improved reporting with scaling factor being reported in the linear and log domains. + +* WMC Tool updates: + + - New command line parameter to allow control on the number of frames per second (default still 50) + + - Export information on all memory allocations occurring during runtime + + - Example script for graphical analysis and profiling of dymanic memory allocation + + - Bugs fixes and code improvements + +Recommendation ITU-T G.191 includes an electronic attachment containing STL2024 and manual. ## Keywords -DSP operators, filters, MNRU, P.50 FB MNRU, open source, reverb, STL2022, G.711, G.722, G.726, G.728, sv56, BS.1770, ESDRU, WMC Tool +DSP operators, filters, MNRU, P.50 FB MNRU, open source, reverb, G.711, G.722, G.726, G.728, sv56, BS.1770, ESDRU, WMC Tool ## 1. Scope diff --git a/doc/manual/STLmanual.tex b/doc/manual/STLmanual.tex index 58185b8..a9cc935 100644 --- a/doc/manual/STLmanual.tex +++ b/doc/manual/STLmanual.tex @@ -18,7 +18,7 @@ \addtolength{\itemsep}{-20pt} % Define headers -\def\ugst_title{ ITU-T Software Tool Library, release 2023} +\def\ugst_title{ ITU-T Software Tool Library, release 2024} \def\us{$\mu$s} \markboth{ \hspace{1cm} \hfill \ugst_title }% { Version: \today \hfill \hspace{1cm} } @@ -61,7 +61,7 @@ \pagenumbering{roman} %============================================================================== -\title{ITU-T Software Tool Library 2023 User's Manual} +\title{ITU-T Software Tool Library 2024 User's Manual} \author{ITU-T Users' Group on Software Tools} %------------------------------------------------------------------------------ @@ -71,7 +71,7 @@ \ruley{100mm} - Copyright \copyright~ 2005, 2006, 2009, 2019, 2022 and 2023 by the International + Copyright \copyright~ 2005, 2006, 2009, 2019, 2022, 2023 and 2024 by the International Telecommunication Union (ITU) \ruley{15mm} diff --git a/doc/manual/bs1770demo.tex b/doc/manual/bs1770demo.tex index 2a2bcbd..1261df3 100644 --- a/doc/manual/bs1770demo.tex +++ b/doc/manual/bs1770demo.tex @@ -103,12 +103,18 @@ \section{Description of the Algorithm} \texttt{fabs( 1.0 - fac / last\_fac ) \textless RELATIVE\_DIFF}, where \texttt{RELATIVE\_DIFF = 0.0001} or when the maximum number of iterations \texttt{MAX\_ITERATIONS = 10} has been reached. +When measuring the loudness of signals with a large dynamic range, it may be desirable to disable the gating function +to obtain the level considering the full signal. This is useful e.g. for noise level adjustment in listening tests +including added background noise. For this reason, the gating function may be disabled using an RMS (Root-Mean-Square) +energy measurement option \texttt{-rms}. Note that this feature is not part of \cite{BS1770}. + {\tt\small \begin{verbatim} double find_scaling_factor( /* o: scaling factor */ const double *gating_block_energy, /* i: gating_block_energy */ const long n_gating_blocks, /* i: Number of gating blocks */ const double lev, /* i: Target level */ + const short rms_flag, /* i: Flag for RMS (no gating) */ double *lev_input, /* o: Input level */ double *lev_obtained /* o: Obtained level */ ) @@ -158,6 +164,7 @@ \section{Usage of bs1770demo} Options: -nchan N Number of channels [1..24] (Default: 1) -lev L Target level LKFS (Default: -26) +-rms Disable gating (for background noise level measurement) -conf xxxx Configuration string: '1' ldspk pos within |elev| < 30 deg, 60 deg <= |azim| <= 120 deg 'L' LFE channel (weight zero) diff --git a/doc/manual/intro.tex b/doc/manual/intro.tex index ae1c10b..07eadbe 100644 --- a/doc/manual/intro.tex +++ b/doc/manual/intro.tex @@ -29,6 +29,8 @@ \chapter{Introduction} In 2023, STL release incorporates an implementation of P.50 fullband MNRU as described in ITU-T Rec. P.810, as well as WMC tool, a tool for automatic instrumentation of speech and audio codecs to measure their computational complexity and memory. +In 2024, the revision of the STL offers additional features and bug fixes to the BS.1770 demo and WMC tool. + Since STL2019, the build toolchain uses CMake to generate platform-dependent and tool-dependent build scripts as well as to execute regression tests for each module in the STL. Modules have been tested on Windows, MacOS and several Linux flavors. @@ -191,6 +193,8 @@ \section{Acknowledgements} For the STL2023, the implementation of the P.50 Fullband MNRU was kindly provided by Mrs Anna Llagostera and Mr Jens Berger from SwissQual AG/Rohde \& Schwarz, with a contribution from NTT on filter routines, the integration into the existing MNRU code and documentation from Ludovic Malfait, and the DC filter and amplitude clipping improvement suggestions from Anssi Ramo (Nokia). The implementation of the WMC tool was kindly provided by Mr Guy Richard and Mr Vladimir Malenovsky from VoiceAge Corporation. +For the STL2024, the improvements to BS.1770 demo and WMC Tool were kindly provided by Mr Erik Norvell from Ericsson and Mr Vladimir Malenovsky from VoiceAge Corporation respectively. + Above all, special thank goes to ITU-T SG16 Counselor Mr~Sim\~ao Ferraz de Campos Neto, the ``father'' of the STL. %============================================================================= @@ -230,6 +234,8 @@ \chapter{Tutorial} \item[STL2009] ITU-T Software Tools Library, release 2009. \item[STL2019] ITU-T Software Tools Library, release 2019. \item[STL2022] ITU-T Software Tools Library, release 2022. +\item[STL2023] ITU-T Software Tools Library, release 2023. +\item[STL2024] ITU-T Software Tools Library, release 2024. \item[UGST] Users' Group on Software Tools, of ITU-T Study Group 16. \end{Descr} diff --git a/doc/manual/wmc_tool.tex b/doc/manual/wmc_tool.tex index 7dbc960..a4c85a9 100644 --- a/doc/manual/wmc_tool.tex +++ b/doc/manual/wmc_tool.tex @@ -56,8 +56,11 @@ \subsection{Usage} note: filename shall point to a .c file containing the print_mem() function -b [--no-backup]: no backup of original files -c dirname [--generate-wmc-files dirname]: copy wmc_auto.h and wmc_auto.c to a user-specified directory + -f value [--frames-per-second value]: set the number of frames per second (default 50.0) \end{Verbatim} +The optional command-line parameters may be used to control either the instrumentation or the couting process. With the \verb|-i| optional argument the WMC tool prints the list of functions that are instrumented. It doesn't run the WMC tool. The parameter \verb|-d| runs the des-instrumentation phase only. The des-instrumentation phase removes all meta-information that has been previously added to the source code with the WMC tool. When \verb|-m| argument is provided the WMC tool adds code calculating ROM and RAM memory consumption and fills the \verb|print_mem()| function to print the statistics about memory usage. When \verb|-m| is provided the user needs to specify the name of the \verb|.c| file containing the \verb|print_mem()| function. The parameter \verb|-b| instructs the WMC tool not to create backup copies of the instrumented \verb|.c| files. The parameter \verb|-c| copies the control files \verb|wmc_auto.h| and \verb|wmc_auto.c| to a user-specified directory. The control files must be added to the project for calculating the complexity and memory consumption of all instrumented source files. The \verb|-f| parameter allows the users to override the default values for the number of frames per second. This value is important for the correct calculation of complexity in "WMOPS". + \subsection{Instrumentation process} \label{ch:instrumentation_process} @@ -107,7 +110,9 @@ \subsubsection{Warnings} \section{Instrumentation of complexity} \label{ch:instrumentation_of_complexity} -The WMC tool only instruments functions but not macros. System functions and functions with names that are considered as basic operations are skipped. The instrumentation mechanism has been designed to be as least intrusive as possible. The instrumentation code is inserted at the beginning of each instrumented line in the source code with a single macro that has the following form \verb|$("ops")| where \verb|ops| is a string of letters and symbols indicating individual operations. The WMC tool parses each source file and calculates the length of each instrumentation string. The maximum length is then used to indent the entire source file to make space for the instrumentation strings. This is shown in the example below. +The instrumentation mechanism has been designed to minimize intrusiveness. It skips system functions and functions labeled as basic operations. When instrumenting \verb|.c| source files, the WMC tool omits macros by default. However, it detects macros defined within the same \verb|.c| source file using the \verb|#define| pragma. Macros defined in external header files and included using \verb|#include| pragma cannot be directly detected. To address this, the instrumentation mechanism employs a heuristic: if a string contains more than 70\% capital letters, it's treated as a macro and skipped during instrumentation. + +The instrumentation code is integrated at the start of every instrumented line in the source code using a singular macro format: \verb|$("ops")|, where \verb|ops| represents a string encompassing individual operations denoted by letters and symbols. Upon parsing each source file, the WMC tool computes the length of each instrumentation string. Subsequently, the maximum length determines the indentation of the entire source file to accommodate the instrumentation strings, as illustrated in the example below. \begin{Verbatim}[fontsize=\small] float calc_shift_value( const float totalStep ) @@ -125,13 +130,13 @@ \section{Instrumentation of complexity} } \end{Verbatim} -It is always possible to remove the instrumentation from the source code with the \verb|-d| command line option. In many cases, the source file will then return to its original non-instrumented state except for whitespace characters and text alignment. The un-instrumentation process is also invoked automatically by the WMC tool as the first step in the instrumentation process. This ensures that the results are identical even when the process is repeated multiple times. This allows the users to make modifications to an already instrumented source code by simply re-instrumenting it again. Note, that the un-instrumentation process does not remove the functions \verb|push_wmops()| and \verb|pop_wmops()| and the system functions. Lines that are preceded by +The removal of instrumentation from the source code can be achieved using the \verb|-d| command line option. In many instances, executing this option restores the source file to its original non-instrumented state, with the exception of whitespace characters and text alignment. The un-instrumentation process is automatically triggered by the WMC tool as the initial step in the instrumentation procedure. This ensures consistent results even with repeated executions. Consequently, users can modify previously instrumented source code by simply re-instrumenting it. It's important to note that the un-instrumentation process does not eliminate the \verb|push_wmops()| and \verb|pop_wmops()| functions, nor does it remove system functions. Lines preceded by { {\em /*AddedByWMC\_Tool*/} } -are removed completely. At the end of the un-instrumentation process, the original indentation is restored. +are removed completely. At the end of the un-instrumentation process the original indentation is restored. If, for any reason, it is necessary to avoid the automatic instrumentation and un-instrumentation of certain parts in the source code, the user may encapsulate such parts in \verb|#define WMC_TOOL_SKIP| \ldots \verb|#undef WMC_TOOL_SKIP| macro pairs. For example @@ -224,18 +229,21 @@ \subsection{Mathematic functions} \verb|sign()| & 1 \\ \verb|round()| & 0 (not supported by the WMC tool) \\ \verb|sqrt()| and \verb|inv_sqrt()| & 10 \\ -\verb|log()|, \verb|log2()| and thier derivatives & 25 \\ +\verb|log()|, \verb|log2()| and other logarithmic functions & 25 \\ \verb|exp()| and \verb|pow()| & 25 \\ \verb|sin()|, \verb|cos()| and all other trigonometric functions & 25 \\ +\verb|frexp()| & 2 \\ +\verb|fmod()| & 18 \\ \hline \end{tabular} \label{tab:cost_of_math_functions} \end{table} + %----------------------------------------------------------------------------- \subsection{User-defined functions} -All user-defined functions in the source code are instrumented with one or more underscore '\verb|_|' symbols appended to their names. The WMC tool will count the number of arguments from the function call and insert a wrapper macro at the top of the source file, after the first \verb|#include| section. See the example below. +All user-defined functions in the source code are instrumented with one or more underscore '\verb|_|' symbols appended to their names. The WMC tool counts the number of arguments in function calls and inserts a wrapper macro at the top of the source file, after the first \verb|#include| section. See the example below. \begin{Verbatim}[fontsize=\small] #include @@ -266,6 +274,49 @@ \subsection{User-defined functions} The WMC tool appends an additional underscore symbol '\verb|_|' in each variant of the user-defined function call. This means that if a function is defined to accept a variable number of arguments the first function call will have one underscore symbol '\verb|_|' appended to its name, the second function call will have two underscore symbols '\verb|__|' appended to its name and so on. The WMC tool supports up to 10 variants (different number of arguments) of the same function. +The WMC tool may encounter difficulties in properly instrumenting one-line functions that are defined as follows + +\begin{Verbatim}[fontsize=\small] + float calculate_vector_norm( float vec[], int_16t size ) { return sum2_f(vec, size); } +\end{Verbatim} + +It's advisable to define the function body on separate lines, like this + +\begin{Verbatim}[fontsize=\small] + float calculate_vector_norm( float vec[], int_16t size ) + { + return sum2_f(vec, size); + } +\end{Verbatim} + +In a local function, all declared variables should be positioned at the start of the function body. Additionally, the initialization of local variables should be segregated from their declaration. For instance, consider the following code snippet, where the WMC tool inserts \verb|$("M")| before \verb|int ch = 0;| + +\begin{Verbatim}[fontsize=\small] + int free_structs(MY_STRUCT_INFO *ptr_dec) + { + if (ptr_dec == NULL) return -1; + +$("M") int ch = 0; + + for (ch = 0; ch < n_channels; ch++) + { + struct_free(&decoder->cfg[ch]->fft_buf); + struct_free(&decoder->cfg[ch]->ifft_buf); + } + + return 0; + } +\end{Verbatim} + +Compiling the instrumented code provided above results in the following error (gcc): + +\begin{Verbatim}[fontsize=\small] +lib_thj/struct_f.c:373:17: error: expected expression before ‘int’ + 125 | $("M") int ch = 0; + | ^~~ +\end{Verbatim} + + %----------------------------------------------------------------------------- \subsection{Operators} @@ -361,7 +412,7 @@ \subsection{Operators} %----------------------------------------------------------------------------- \subsection{Manual instrumentation} -It was already shown in the previous section in this document that it is possible to avoid the automatic instrumentation by encapsulating parts of the source code with +As demonstrated in the preceding section of this document, it's possible to bypass automatic instrumentation by encapsulating sections of the source code with \begin{Verbatim}[fontsize=\small] #define WMC_TOOL_SKIP @@ -435,7 +486,7 @@ \subsection{Complexity of functions and functional blocks} } \end{Verbatim} -The string inside each \verb|push_wmops()| macro shall be unique in the entire project and reflect what is being measured. It does not need to be the same as the name of the function in which it is used. The macro \verb|pop_wmops()| must \textbf{ALWAYS} be used to terminate the complexity counters associated with each \verb|push_wmops()| macro. The WMC tool supports nesting of these macro pairs. Note, that the \verb|push_wmops()| and the \verb|pop_wmops()| macros do not need to be encapsulated within the \verb|#define WMC_TOOL_SKIP| \ldots \verb|#undef WMC_TOOL_SKIP| macro pairs. +The \verb|push_wmops()| macro must be placed after the declaration of local variables. The string inside each \verb|push_wmops()| macro shall be unique in the entire project and reflect what is being measured. It does not need to be the same as the name of the function in which it is used. The macro \verb|pop_wmops()| must \textbf{ALWAYS} be used to terminate the complexity counters associated with each \verb|push_wmops()| macro. The WMC tool supports nesting of these macro pairs. Note, that the \verb|push_wmops()| and the \verb|pop_wmops()| macros do not need to be encapsulated within the \verb|#define WMC_TOOL_SKIP| \ldots \verb|#undef WMC_TOOL_SKIP| macro pairs. %----------------------------------------------------------------------------- \subsection{Printing statistics about computational complexity} diff --git a/src/bs1770demo/CMakeLists.txt b/src/bs1770demo/CMakeLists.txt index 9a9c8fc..daba5f8 100644 --- a/src/bs1770demo/CMakeLists.txt +++ b/src/bs1770demo/CMakeLists.txt @@ -11,3 +11,9 @@ add_test(bs1770demo2-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -equiv add_test(bs1770demo3 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/bs1770demo -lev -16 -conf 11L000 test_data/sine_noise_test.pcm test_data/sine_noise_test.16LKFS.11L000.test.pcm) add_test(bs1770demo3-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -equiv 159 -q test_data/sine_noise_test.16LKFS.11L000.test.pcm test_data/sine_noise_test.16LKFS.11L000.pcm) + +add_test(bs1770demo4 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/bs1770demo -lev -26 test_data/sine_ramp.pcm test_data/sine_ramp.26LKFS.test.pcm) +add_test(bs1770demo4-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -equiv 115 -q test_data/sine_ramp.26LKFS.test.pcm test_data/sine_ramp.26LKFS.pcm) + +add_test(bs1770demo5 ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/bs1770demo -rms -lev -26 test_data/sine_ramp.pcm test_data/sine_ramp.26LKFSrms.test.pcm) +add_test(bs1770demo5-verify ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/signal-diff -equiv 206 -q test_data/sine_ramp.26LKFSrms.test.pcm test_data/sine_ramp.26LKFSrms.pcm) diff --git a/src/bs1770demo/bs1770demo.c b/src/bs1770demo/bs1770demo.c index 0d51d37..84ec2f7 100644 --- a/src/bs1770demo/bs1770demo.c +++ b/src/bs1770demo/bs1770demo.c @@ -19,6 +19,8 @@ #define MAX_ITERATIONS 10 #define RELATIVE_DIFF 0.0001 #define MAX_CH_NUMBER 24 +#define ZERO_BLOCKS (1000.0f) /* Constant to signal that zero blocks passed the gating threshold. + (Only results within [-Inf,LKFS_OFFSET] are valid) */ /* Channel weights for default channel ordering. Assumes channels are ordered as in 22.2 WAVE files: @@ -100,6 +102,7 @@ void usage() fprintf( stdout, "Options:\n" ); fprintf( stdout, "-nchan N Number of channels [1..24] (Default: 1)\n" ); fprintf( stdout, "-lev L Target level LKFS (Default: -26)\n" ); + fprintf( stdout, "-rms Disable gating (for background noise level measurement)\n" ); fprintf( stdout, "-conf xxxx Configuration string:\n") ; fprintf( stdout, " '1' ldspk pos within |elev| < 30 deg, 60 deg <= |azim| <= 120 deg\n" ); fprintf( stdout, " 'L' LFE channel (weight zero)\n" ); @@ -271,7 +274,8 @@ double gated_loudness( /* o: gated loudness */ const double *gating_block_energy, /* i: gating_block_energy */ const double fac, /* i: Scaling factor */ const long n_gating_blocks, /* i: Number of gating blocks */ - const double threshold /* i: LKFS threshold */ + const double threshold, /* i: LKFS threshold */ + const short rms_flag /* i: Flag for RMS (no gating) */ ) { long i; @@ -280,32 +284,40 @@ double gated_loudness( /* o: gated loudness */ count = 0; for( i = 0; i < n_gating_blocks; i++ ) { - if( (LKFS_OFFSET + 10 * log10( gating_block_energy[i] * fac * fac )) > threshold ) + if( ( (LKFS_OFFSET + 10 * log10( gating_block_energy[i] * fac * fac )) > threshold ) || rms_flag ) { energy += gating_block_energy[i] * fac * fac; count++; } } - return LKFS_OFFSET + 10 * log10( energy / count ); + if ( count == 0 ) + { + return ZERO_BLOCKS; /* Send invalid value to indicate that zero blocks were above threshold */ + } + else + { + return LKFS_OFFSET + 10 * log10(energy / count); + } } double gated_loudness_adaptive( /* o: gated loudness, using adaptive threshold */ const double *gating_block_energy, /* i: gating_block_energy */ const double fac, /* i: Scaling factor */ - const long n_gating_blocks /* i: Number of gating blocks */ + const long n_gating_blocks, /* i: Number of gating blocks */ + const short rms_flag /* i: Flag for RMS (no gating) */ ) { double relative_threshold; double gated_loudness_final; /* Find scaling factor */ - relative_threshold = gated_loudness( gating_block_energy, fac, n_gating_blocks, ABSOLUTE_THRESHOLD ) + RELATIVE_THRESHOLD_OFFSET; + relative_threshold = gated_loudness( gating_block_energy, fac, n_gating_blocks, ABSOLUTE_THRESHOLD, rms_flag ) + RELATIVE_THRESHOLD_OFFSET; if( ABSOLUTE_THRESHOLD > relative_threshold ) { relative_threshold = ABSOLUTE_THRESHOLD; } - gated_loudness_final = gated_loudness( gating_block_energy, fac, n_gating_blocks, relative_threshold ); + gated_loudness_final = gated_loudness( gating_block_energy, fac, n_gating_blocks, relative_threshold, rms_flag ); return gated_loudness_final; } @@ -314,6 +326,7 @@ double find_scaling_factor( /* o: scaling factor */ const double *gating_block_energy, /* i: gating_block_energy */ const long n_gating_blocks, /* i: Number of gating blocks */ const double lev, /* i: Target level */ + const short rms_flag, /* i: Flag for RMS (no gating) */ double *lev_input, /* o: Input level */ double *lev_obtained /* o: Obtained level */ ) @@ -329,7 +342,7 @@ double find_scaling_factor( /* o: scaling factor */ while( (fabs( 1.0 - fac / last_fac ) > RELATIVE_DIFF) && (itr < MAX_ITERATIONS) ) { /* Find scaling factor */ - gated_loudness_final = gated_loudness_adaptive( gating_block_energy, fac, n_gating_blocks ); + gated_loudness_final = gated_loudness_adaptive( gating_block_energy, fac, n_gating_blocks, rms_flag ); last_fac = fac; fac *= pow( 10.0, (lev - gated_loudness_final) / 20.0 ); if (itr == 0 ) @@ -397,12 +410,15 @@ int main(int argc, char **argv ) double fac; double G[MAX_CH_NUMBER]; short zero_input_flag; + short zero_blocks_flag; + short rms_flag; lev_target = -26; /* Default target level */ i = 1; conf = NULL; nchan = -1; zero_input_flag = 1; + rms_flag = 0; /* Command line parsing */ if( argc == 1 ) @@ -436,6 +452,11 @@ int main(int argc, char **argv ) } i += 2; } + else if( strcmp( argv[i], "-rms" ) == 0 ) + { + rms_flag = 1; + i += 1; + } else if( strcmp( argv[i], "-conf" ) == 0 ) { conf = argv[i + 1]; @@ -574,7 +595,10 @@ int main(int argc, char **argv ) } } - if( !zero_input_flag ) + /* Check if all blocks are below ABSOLUTE_THRESHOLD */ + zero_blocks_flag = (ZERO_BLOCKS == gated_loudness(gating_block_energy, 1.0, n_gating_blocks, ABSOLUTE_THRESHOLD, rms_flag) ); + + if ( !zero_input_flag && !zero_blocks_flag ) { if( f_output != NULL ) @@ -583,7 +607,7 @@ int main(int argc, char **argv ) /* Find scaling factor */ /* Since a rescaling affects the relative gating threshold the factor is found through an iterative function */ - fac = find_scaling_factor( gating_block_energy, n_gating_blocks, lev_target, &lev_input, &lev_obtained ); + fac = find_scaling_factor( gating_block_energy, n_gating_blocks, lev_target, rms_flag, &lev_input, &lev_obtained ); /* Apply scaling */ rewind( f_input ); @@ -602,6 +626,7 @@ int main(int argc, char **argv ) fprintf( stdout, "Target level: %.6f\n", lev_target ); fprintf( stdout, "Obtained level: %.6f\n", lev_obtained ); fprintf( stdout, "Scaling factor: %.6f\n", fac ); + fprintf( stdout, "Scaling [dB]: %.6f\n", 20 * log10( fac ) ); fprintf( stdout, "\n--> Done processing %ld samples\n", length_total ); if( clip > 0 ) { @@ -613,14 +638,21 @@ int main(int argc, char **argv ) else { /* No output file is specified -- find the input level */ - lev_input = gated_loudness_adaptive( gating_block_energy, 1.0, n_gating_blocks ); + lev_input = gated_loudness_adaptive( gating_block_energy, 1.0, n_gating_blocks, rms_flag ); fprintf( stdout, "Input level: %.6f\n", lev_input ); fprintf( stdout, "\n--> Done processing %ld samples\n", length_total ); } } else { - fprintf( stderr, "*** Warning: All non-LFE channels are zero\n" ); + if ( zero_input_flag ) + { + fprintf(stderr, "*** Warning: All non-LFE channels are zero\n"); + } + else + { + fprintf(stderr, "*** Warning: All non-LFE channels are below absolute gating threshold %.2f\n", ABSOLUTE_THRESHOLD); + } if( f_output != NULL ) { fprintf( stderr, "*** Scaling of zero input not possible, exiting ..\n" ); diff --git a/src/bs1770demo/supplementary_info/generate_test_signal.m b/src/bs1770demo/supplementary_info/generate_test_signal.m index 2e37b2e..e1e4f0b 100644 --- a/src/bs1770demo/supplementary_info/generate_test_signal.m +++ b/src/bs1770demo/supplementary_info/generate_test_signal.m @@ -16,10 +16,10 @@ rng(1); -A = dbov_fac(y,-26); +A = 0.070880495302845; N = randn(size(y)); -AN = dbov_fac(N,-26); +AN = 1.636408779315202e+03; Y(1,:) = A * 32767 * sin(2*pi*997*t); Y(2,:) = 0.58 * A * 32767 * sin(2*pi*1033*t); @@ -31,3 +31,11 @@ fid = fopen('sine_noise_test.pcm','w'); fwrite(fid,Y,'short'); fclose(fid); + +%% + +x = sin(2*pi*f*t) .* logspace(0,4,3*fs); + +fid = fopen('sine_ramp.pcm','w'); +fwrite(fid,x,'short'); +fclose(fid); diff --git a/src/bs1770demo/test_data/sine_ramp.26LKFS.pcm b/src/bs1770demo/test_data/sine_ramp.26LKFS.pcm new file mode 100644 index 0000000..ac1fd77 Binary files /dev/null and b/src/bs1770demo/test_data/sine_ramp.26LKFS.pcm differ diff --git a/src/bs1770demo/test_data/sine_ramp.26LKFSrms.pcm b/src/bs1770demo/test_data/sine_ramp.26LKFSrms.pcm new file mode 100644 index 0000000..6aaf78f Binary files /dev/null and b/src/bs1770demo/test_data/sine_ramp.26LKFSrms.pcm differ diff --git a/src/bs1770demo/test_data/sine_ramp.pcm b/src/bs1770demo/test_data/sine_ramp.pcm new file mode 100644 index 0000000..747db5b Binary files /dev/null and b/src/bs1770demo/test_data/sine_ramp.pcm differ diff --git a/src/wmc_tool/HISTORY.md b/src/wmc_tool/HISTORY.md new file mode 100644 index 0000000..456511f --- /dev/null +++ b/src/wmc_tool/HISTORY.md @@ -0,0 +1,69 @@ +# History of the WMC tool + +## v1.0 + + * initial version of the WMC tool + +## v1.1 + + * added support for PROM Counting + * added support for Table ROM Instrumentation + * added support for stack counting + * added progress bar (0-100%) + * added support for `S("string")` macro in manually-instrumented sections + +## v1.2 + + * added Unident mode to remove unused left margin + * added automatic conversion of TABs to spaces + * added a command-line switch to disable all warnings (`/dw99`) + + * modified the atomatically-generated file "wmc_auto.h" to eliminate warnings when compiled with `gcc` + * removed `#pragma WMC_TOOL_MESSAGE` in the `rom_*.c` files + * removed `#pragma WMC_TOOL_MESSAGE` for manually-instrumented sections + + * changed the default PROM counting weights to those specified in [S4-110479 - FTO - On Program ROM measurement for EVS standardization.doc] ([https://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_64/docs/S4-110479.zip) + * fix of a small bug where using `/op2`, `/op3` crashes the WMC tool + * added support for Windows 8 command line and Cygwin V1.7.17 and later versions + * fix for a bug where a `$("[]M[]")` was inserted at the end of some C source files when it was re-instrumented + +## v1.3 + + * break in early-return out of .each early with return false + * prevent adding unnecessary space by the functions `Move_on_Chars()` and `Skip_Chars()` + * optimize the function `Find_Region()` to improve the speef of instrumentation + * optimize the function calculating the next pointer address after hitting the search target + * order macro names, system functions, etc. in the highest priority order + * combine `strlno` and `strcno` inside `Make_Position_String()` + * optimize the usage of the function `Instrument_Names()` inside `Find_Keywords()` and `Find_Calls()` + * remove the cases where `item_link` is always NULL + +## v1.4 + + * first version uploaded to the Open-ITU/STL Github repository + * remove obsolete parts of the source code (e.g. FLC) + + * bug in PROM calculation fixed + * command-line options modified (`/ic` and `/op` removed) + * memory instrumentation (PROM, Table ROM, static RAM and stack) integrated within the WMC tool (auxiliary files `PROM_Size_xxx.c` no longer generated) + * merging and renaming of files: + ** `wmops.h` and `wmops.c` -> `wmc_auto.h` and `wmc_auto.c` + ** `memory.c` -> `wmc_auto.c` + ** `mem_count.h` and `mem_count.c` -> `wmc_auto.h` and `wmc_auto.c` + ** `wmc_auto.h` and `wmc_auto.c` are optionally generated by the WMC tool with the `./wmc_tool /cp dir_name` command-line option + * PROM consumption calculated during instrumentation and added at the end in each `.c` file + * total PROM consumption may be printed with the function `print_mem()` + * re-factoring of the Table ROM instrumentation, calculation and reporting + +## v1.5 + + * fixed compilation issues on MaC platforms + * fixed a problem where `NaN` was printed for a non-instrumented function having zero complexity + * dynamic allocation and re-allocation of all internal buffers tracking both heap and stack call trees + * introduction of `-f FRAME_PER_SECONDS` command-line option allowing the user to choose the number of frames per second (default is still 50.0) + * fixed a problem when `push_wmops()` was called twice when `WMOPS_DETAILS` was activated + * raise an error message if `#define WMC_TOOL_SKIP` is not paired with `#undef WMC_TOOL_SKIP` + * export information about all dynamic allocations/de-allocations occuring during the runtime of the codec to a `.csv` file + * added an exemplary Python script `mem_analysis.py` for graphical analysis and profiling of dynamic memory alloations based on the generated `.csv` file + * added support for counting complexity and PROM size of BASOP operations and BASOP functions within floating-point source code + \ No newline at end of file diff --git a/src/wmc_tool/README.md b/src/wmc_tool/README.md index 4180f2c..4731e71 100644 --- a/src/wmc_tool/README.md +++ b/src/wmc_tool/README.md @@ -21,6 +21,7 @@ This software is protected by copyright law and by international treaties. The s ## History 2022-10-15 First release v1.4 +2023-10-24 Update to v1.5 (fixed small errors, compilation issues, added optimizations of the source code, added instrumentation of BASOP instructions and operators) ## Authors @@ -42,6 +43,7 @@ The files `wmc_auto_h.txt` and `wmc_auto_c.txt` contain functions and definition ### Unix-based systems To build the project on Unix-based platforms invoke the following commands from the top-level directory containing the file `CMakeLists.txt`: + ``` mkdir build cd build @@ -54,6 +56,7 @@ The binary file `wmc_tool` shall be created in the top-level directory. ### Windows system To build the project on MS Windows use the `cmake` command with `-G` option specifying the target platform. For example, to build project files for 64-bit MSVC 2019, invoke the following commands from the top-level directory containing the file `CMakeLists.txt`: + ``` md build cd build @@ -63,6 +66,25 @@ msbuild wmc_tool.sln The executable file `wmc_tool.exe` shall be created in the top-level directory. Note, that it is recommended to run these commands from the `Developer Command Prompt for VS2019` opened in `Administrator` mode. This ensures that all paths to libraries including the SDK can be found by the `cmake` command. This can also be verified with the `vswhere` command. +### Mac OS X system + +To build the project on OS X platforms for both, ARM and Intel architectures, invoke the following commands from the top-level directory containing the file `CMakeLists.txt`: + +``` +mkdir build +cd build +cmake -G "Xcode" "-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" .. +cmake --build . -j +``` + +At this point the binary is not signed yet and needs the following operations before it can be executed. +- Open `wmc_tool` with Finder -> Open (an error prompt should pop-up) +- Go to System Settings -> Privacy & Security and allow the `wmc_tool` to run +- Add execution rights to `wmc_tool` with: `chmod +x wmc_tool` + +The `wmc_tool` should now be ready for execution. + + ## Testing To verify the conformance of the WMC tool it's possible to invoke the `ctest` command from the `build` directory. On Windows platforms it may be necessary to append the config type with the `-C` command-line option. If no specific config type has been specified when running the `cmake` command, then `ctest -C Debug` shall be used for testing. This runs a series of pre-defined tests using some exemplary `.c` files located in the `testv/src` folder. The instrumented files are compared with their respective references located in the `testv/ref` folder. In case of test failure it's possible to re-run the test with the `--verbose` command-line option to see the reason of failure. Note, that `ctest` uses the Python wrapper script `testv/test_wmc_tool.py` for copying the source files, running the WMC tool binary (executable) file, comparing the output to the reference and cleaning up the work. diff --git a/src/wmc_tool/c_parser.cpp b/src/wmc_tool/c_parser.cpp index e204942..79f1101 100644 --- a/src/wmc_tool/c_parser.cpp +++ b/src/wmc_tool/c_parser.cpp @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -110,62 +110,49 @@ MANUAL_COUNTING_MACROS_STRING \ AUTO_COUNTING_MACROS_STRING -#define WMOPS_COUNTLIB_FUNCTS_STRING \ - "reset_wmops push_wmops pop_wmops update_wmops print_wmops " -#define OTHER_COUNTLIB_FUNCTS_STRING \ - "Dyn_Mem_Init Dyn_Mem_Exit Dyn_Mem_Exit_noprint " \ - "Dyn_Mem_In Dyn_Mem_Add Dyn_Mem_Out " \ - "Sta_Mem_Init Sta_Mem_Exit Sta_Mem_Exit_noprint Sta_Mem_Add " \ - "P_Dyn_Mem_Init P_Dyn_Mem_Exit P_Dyn_Mem_Exit_noprint " \ - "P_Dyn_Mem_In P_Dyn_Mem_Add P_Dyn_Mem_Out " \ - "P_Sta_Mem_Init P_Sta_Mem_Exit P_Sta_Mem_Exit_noprint P_Sta_Mem_Add " \ - "DYN_MEM_IN DYN_MEM_ADD DYN_MEM_OUT " -#define COUNTLIB_FUNCTS_STRING \ - WMOPS_COUNTLIB_FUNCTS_STRING \ - OTHER_COUNTLIB_FUNCTS_STRING +#define WMOPS_FUNCTS_STRING \ + "reset_wmops push_wmops pop_wmops update_wmops print_wmops print_mem " \ + "rsize Get_Const_Data_Size Print_Const_Data_Size " #define COUNTING_CODE_STRING \ COUNTING_MACROS_STRING \ - COUNTLIB_FUNCTS_STRING - -#define TOOL_FUNCTS_STRING \ - "rsize " \ - "Get_Const_Data_Size " \ - "Print_Const_Data_Size " \ - "print_mem " + WMOPS_FUNCTS_STRING #define SYSTEM_ALLOC_FUNCTS_STRING \ "malloc calloc free " -#define SYSTEM_FUNCTS_STRING \ - "printf fprintf " \ - "fopen fclose fwrite fread " \ - "exit " \ - "assert " \ - "push_indice set_indice get_indice exist_indice " \ - "reset_indices write_indices read_indices " \ - "read_bitstream_info reset_stack push_stack " - -#define MATH_FUNCTS_STRING \ - "abs fabs labs " \ - "floor " \ - "sqrt sqrtf " \ - "pow exp " \ - "log log10 " \ - "cos sin tan " \ - "acos asin atan atan2 " \ - "cosh sinh tanh " \ - "fmod " \ - "min max Min Max MIN MAX " \ - "sqr Sqr SQR " \ - "square Square SQUARE " \ - "sign Sign SIGN " \ - "inv_sqrt " \ - "log_base_2 log2_f " \ - "_round round_f " \ - "_squant " \ - "set_min set_max " \ - "mac msu " +#define SYSTEM_FUNCTS_STRING \ + "printf fprintf " \ + "fopen fclose fwrite fread " \ + "assert exit " + +#define MATH_FUNCTS_STRING \ + "abs fabs fabsf labs " \ + "floor floorf " \ + "sqrt sqrtf inv_sqrt inv_sqrtf " \ + "pow powf exp expf " \ + "log logf log10 log10f log_base_2 log2 log2f log2_f " \ + "cos cosf sin sinf tan tanf " \ + "acos acosf asin asinf atan atanf atan2 atan2f " \ + "cosh coshf sinh sinhf tanh tanhf " \ + "fmod fmodf frexp frexpf " \ + "min max Min Max MIN MAX " \ + "sqr Sqr SQR square Square SQUARE " \ + "sign Sign SIGN " \ + "_round round round_f roundf " \ + "set_min set_max " + +#define BASOP_FUNCTS_STRING \ + "add sub abs_s shl shr extract_h extract_l mult L_mult negate round " \ + "L_mac L_msu L_macNs L_msuNs L_add L_sub L_add_c L_sub_c L_negate L_shl L_shr " \ + "mult_r shr_r mac_r msu_r L_deposit_h L_deposit_l L_shr_r L_abs L_sat norm_s div_s " \ + "norm_l move16 move32 Logic16 Logic32 Test s_max s_min L_max L_min L40_max " \ + "L40_min shl_r L_shl_r L40_shr_r L40_shl_r norm_L40 L40_shl L40_shr L40_negate " \ + "L40_add L40_sub L40_abs L40_mult L40_mac mac_r40 L40_msu msu_r40 Mpy_32_16_ss " \ + "Mpy_32_32_ss L_mult0 L_mac0 L_msu0 lshl lshr L_lshl L_lshr L40_lshl L40_lshr " \ + "s_and s_or s_xor L_and L_or L_xor rotl rotr L_rotl L_rotr L40_set L40_deposit_h " \ + "L40_deposit_l L40_deposit32 Extract40_H Extract40_L L_Extract40 L40_round " \ + "L_saturate40 round40 If Goto Break Switch For While Continue L_mls div_l i_mult " #define WMOPS_LIB_INCLUDE_STRING \ "wmc_auto.h" @@ -199,15 +186,6 @@ #define RETURN_KW_STRING "return" -/***************************************** - * Fixed Point Macros Lacking a ';' - *****************************************/ - -#define NON_STANDARD_FXP_MACROS_STRING \ - "BASOP_SATURATE_WARNING_ON " \ - "BASOP_SATURATE_WARNING_OFF " \ - "BASOP_SATURATE_ERROR_ON " \ - "BASOP_SATURATE_ERROR_OFF " /*-------------------------------------------------------------------* * Local Typedefs @@ -2520,6 +2498,9 @@ static TOOL_ERROR Find_Keywords( { /* Yes */ /* Try Uppercase Version */ for (ns = kw_name; *ns != NUL_CHAR; *ns = toupper(*ns), ns++); + + /* Uppercase version is recognized as BASOP operation -> do not instrument */ + item_type = ITEM_INSTRUMENTATION_OFF; } else if (run == 2) { @@ -2591,6 +2572,7 @@ static TOOL_ERROR Find_Keywords( { /* Set Name End */ ne = ns + kw_name_len; + /* Add Keyword Region */ if ( ( ErrCode = Add_Region( ParseTbl_ptr, item_type + /* Keywords that Compute to Constants are stripped of KW Attribute. */ @@ -2680,8 +2662,7 @@ static TOOL_ERROR Find_Keywords( dp = pe; } /* Skip Blanks to the Left (this cannot fail) */ - pe = Skip_Chars( pe - 1, BLANK_CHARS, ParseTbl_ptr, - ITEM_ANY, ITEM_MOVED_OVER, BACKWARDS ); + pe = Skip_Chars( pe - 1, BLANK_CHARS, ParseTbl_ptr, ITEM_ANY, ITEM_MOVED_OVER, BACKWARDS ); } /* Keyword Name has a Delimiter? */ if ( keywords[i].kw_delim != NUL_CHAR ) @@ -2747,15 +2728,17 @@ static TOOL_ERROR Find_Keywords( } /* Add Keyword Expression Region */ - if ( ( ErrCode = Add_Region( ParseTbl_ptr, + /* !!! VM: added ITEM_INSTRUMENTATION_OFF to mark a non-instrumented BASOP keyword expression region !!! */ + if ( ( ErrCode = Add_Region( ParseTbl_ptr, (item_type == ITEM_INSTRUMENTATION_OFF ? ITEM_INSTRUMENTATION_OFF : 0) + /* Keywords Expressions that Compute to Constants are stripped of KW_EXPR Attribute */ /* Added because when 'sizeof' is marked as a KW Expresion, instrumentation of something */ /* like 'sizeof(float) * 2' would be instrumented between the ')' and the '2'.*/ - ( ( keywords[i].kw_type & ITEM_CONSTANT ) ? 0 : ITEM_KW_EXPR ) | keywords[i].expr_type, ps, pe + 1 ) ) != NO_ERR ) + (( ( keywords[i].kw_type & ITEM_CONSTANT ) ? 0 : ITEM_KW_EXPR ) | keywords[i].expr_type), ps, pe + 1 ) ) != NO_ERR ) { goto ret; } } + /* Continue after Arguments or Value End */ ne = pe + 1; } @@ -3149,12 +3132,6 @@ static TOOL_ERROR Find_Data_Declarations( /* Skip Blanks to the Right */ ptr = Skip_Chars( start, BLANK_CHARS, ParseTbl_ptr ); } - /* Fixed Point Macros Lacking ';'? */ - if ( ( start = memwordcmp( ptr, NON_STANDARD_FXP_MACROS_STRING ) ) != NULL ) - { /* Yes */ - /* Done */ - break; - } /* Any of the Known Data Types, Type Definition Type Modifier or Storage Class? */ if ( ( start = memwordcmp( ptr, DATA_DEF_STRING ) ) != NULL ) @@ -3361,6 +3338,7 @@ static TOOL_ERROR Find_Data_Declarations( /* Done */ break; } + /* Go to End of Statement */ /* !!!!! Incorrect when have 'int a' then 'BRANCH(1)', 'a += 2', ... on Next Line (Known Limitation)*/ if ( ( start = Goto_EOS( start, ParseTbl_ptr ) ) == NULL ) @@ -3370,11 +3348,14 @@ static TOOL_ERROR Find_Data_Declarations( ErrCode = Expected_EOS( ptr ); goto ret; } + /* Skip Blanks to the Right */ ptr = Skip_Chars( start + 1, BLANK_CHARS, ParseTbl_ptr ); } + /* Set Region End */ ParseRecord.item_end = ptr; + /* Is Region Empty? */ if ( !Is_Empty_Region( ParseRecord.item_start, ptr, ParseTbl_ptr ) ) { @@ -3384,8 +3365,10 @@ static TOOL_ERROR Find_Data_Declarations( goto ret; } } + /* Change Data Declaration Region Type */ ParseRecord.item_type = ITEM_DATA_DECL_SUB | ITEM_WARNING; + /* Go to Next Code Block */ start = Find_String( ptr, "{", ParseTbl_ptr, ITEM_ANY ); } while ( start != NULL && start < end ); @@ -4108,6 +4091,7 @@ static TOOL_ERROR Find_Constants( memset( str, 0, sizeof( str ) ); memmove( str, ptr2 - LEN, LEN ); memmove( str + LEN + 1, ptr, LEN ); + for ( temp = 0; temp < sizeof( str ); temp++ ) { if ( IS_EOL_CHAR( str[temp] ) || IS_RESERVED_CHAR( str[temp] ) ) @@ -4115,8 +4099,8 @@ static TOOL_ERROR Find_Constants( str[temp] = ' '; } } - printf( "%s: Number=%s#%s#\n", ptr2 == ptr4 ? "+/- is Oper" : "+/- is Cste", - str, memstr( ptr2, ptr ) /*, str+LEN+1*/ ); + + fprintf( stdout, "%s: Number=%s#%s#\n", ptr2 == ptr4 ? "+/- is Oper" : "+/- is Cste", str, memstr( ptr2, ptr ) /*, str+LEN+1*/ ); } #endif } @@ -4164,16 +4148,19 @@ static Item_Type Get_Call_Type( /* Not a Function Call */ return ITEM_NONE; } + /* Any of the System Functions? */ if ( memwordcmp( name_start, SYSTEM_FUNCTS_STRING ) != NULL ) { /* Yes */ return ITEM_FUNC_SYSTEM | ITEM_SKIPPED; } + /* Any of the System Allocation Functions? */ if ( memwordcmp( name_start, SYSTEM_ALLOC_FUNCTS_STRING ) != NULL ) { /* Yes */ return ITEM_FUNC_SYSTEM; } + /* Any of the Instrumented System Allocation Functions? */ if ( memwordcmp( name_start, ins_sys_alloc_funcs_string ) != NULL ) { /* Yes */ @@ -4185,36 +4172,43 @@ static Item_Type Get_Call_Type( { /* Yes */ return ITEM_FUNC_MATH; } + /* Any of the Instrumented Math Functions? */ if ( memwordcmp( name_start, ins_math_funcs_string ) != NULL ) { /* Yes */ return ITEM_FUNC_MATH | ITEM_INSTRUMENTED; } + /* Any of the Manual Counting Macros? */ if ( memwordcmp( name_start, MANUAL_COUNTING_MACROS_STRING ) != NULL ) { /* Yes */ return ITEM_FUNC_COUNTERS_MAN | ITEM_INSTRUMENTATION | ITEM_SKIPPED; } + /* Any of the Left Automatic Counting Macros? */ if ( memwordcmp( name_start, AUTO_LEFT_COUNTING_MACRO_STRING ) != NULL ) { /* Yes */ return ITEM_FUNC_COUNTERS_AUTO_L | ITEM_INSTRUMENTATION | ITEM_SKIPPED; } + /* Any of the Right Automatic Counting Macros? */ if ( memwordcmp( name_start, AUTO_RIGHT_COUNTING_MACRO_STRING ) != NULL ) { /* Yes */ return ITEM_FUNC_COUNTERS_AUTO_R | ITEM_INSTRUMENTATION | ITEM_SKIPPED; } - /* Any of the Counting Library Functions? */ - if ( memwordcmp( name_start, COUNTLIB_FUNCTS_STRING ) != NULL ) + + /* Any of the WMOPS Library Functions or Macros? */ + if ( memwordcmp( name_start, WMOPS_FUNCTS_STRING) != NULL ) { /* Yes */ return ITEM_FUNC_COUNT_LIB | ITEM_SKIPPED; } - /* Any of the ROM Counting Macros? */ - if ( memwordcmp( name_start, TOOL_FUNCTS_STRING ) != NULL ) + + /* Any of the BASOP Functions or Macros? */ + if (memwordcmp(name_start, BASOP_FUNCTS_STRING) != NULL) { /* Yes */ - return ITEM_FUNC_COUNT_LIB | ITEM_SKIPPED; + return ITEM_FUNC_BASOP | ITEM_INSTRUMENTATION_OFF; } + return ITEM_FUNC_PROJECT; } @@ -4346,8 +4340,8 @@ static TOOL_ERROR Find_Calls( { goto ret; } - /* Counting Macro or Function? */ - if ( item_type & ( ITEM_FUNC_COUNTERS | ITEM_FUNC_COUNT_LIB ) ) + /* Counting Macro, Couting Function or BASOP Function? */ + if ( item_type & ( ITEM_FUNC_COUNTERS | ITEM_FUNC_COUNT_LIB | ITEM_FUNC_BASOP ) ) { /* Yes */ /* Get Optional End of Statement @@ -4688,6 +4682,7 @@ static TOOL_ERROR Instrument_Keywords( /* Get Parse Table Address (for clarity) */ ParseTbl_ptr = &ParseCtx_ptr->ParseTbl; + /* Get PROM Ops Weights (for clarity) */ prom_ops_weights_ptr = &PROM_Ops_Weights[ParseCtx_ptr->PROMOpsWeightsSet]; @@ -4713,8 +4708,8 @@ static TOOL_ERROR Instrument_Keywords( { /* No */ /* Instrument After (by default) */ ptr = ParseRec_ptr->item_end; - /* Is it a 'while' that is part of a 'do' Block? */ + /* Is it a 'while' that is part of a 'do' Block? */ /* Insert Instrumentation Character */ if ( ( ErrCode = Add_Insertion( &ParseCtx_ptr->InsertTbl, ptr, WORD_INSTRUMENT_STRING ) ) != NO_ERR ) { @@ -4743,12 +4738,14 @@ static TOOL_ERROR Instrument_Keywords( { goto ret; } + if ( ( ErrCode = Add_Insertion( &ParseCtx_ptr->InsertTbl, ParseRec_ptr->item_end, ")" ) ) != NO_ERR ) { goto ret; } + /* Add Warning */ ParseRec_ptr->item_type |= ITEM_WARNING; } @@ -4765,11 +4762,22 @@ static TOOL_ERROR Instrument_Keywords( } /* Count Program Memory */ - if ( item_type == ITEM_KEYWORD_FOR ) + //if ( item_type == ITEM_KEYWORD_FOR ) + // loops++, ParseCtx_ptr->PROMSize += prom_ops_weights_ptr->loop; + //else if ( item_type == ITEM_KEYWORD_WHILE ) + // whiles++, ParseCtx_ptr->PROMSize += prom_ops_weights_ptr->branch * 2; + //else if ( item_type & ( ITEM_KEYWORD_CONTROL | ITEM_KEYWORD_IS_JUMP ) ) + // jumps++, ParseCtx_ptr->PROMSize += prom_ops_weights_ptr->branch; + } + + /* Count Program Memory */ /* !!! VM: Moved to this place to count PROM size even for non-instrumented keywords */ + if ( Find_Region(ParseRec_ptr->item_start, ParseTbl_ptr, ITEM_SKIPPED) < 0 ) + { + if (item_type == ITEM_KEYWORD_FOR) loops++, ParseCtx_ptr->PROMSize += prom_ops_weights_ptr->loop; - else if ( item_type == ITEM_KEYWORD_WHILE ) + else if (item_type == ITEM_KEYWORD_WHILE) whiles++, ParseCtx_ptr->PROMSize += prom_ops_weights_ptr->branch * 2; - else if ( item_type & ( ITEM_KEYWORD_CONTROL | ITEM_KEYWORD_IS_JUMP ) ) + else if (item_type & (ITEM_KEYWORD_CONTROL | ITEM_KEYWORD_IS_JUMP)) jumps++, ParseCtx_ptr->PROMSize += prom_ops_weights_ptr->branch; } } @@ -5429,11 +5437,13 @@ static TOOL_ERROR Instrument_Operators( /* Erase Operator Insert Table */ OperInsTbl.Size = 0; + /* Initialize (No Memory Allocated by Default) */ OperInsTbl.MaxSize = 0; /* Get Parse Table Address (for clarity) */ ParseTbl_ptr = &ParseCtx_ptr->ParseTbl; + /* Get PROM Ops Weights (for clarity) */ prom_ops_weights_ptr = &PROM_Ops_Weights[ParseCtx_ptr->PROMOpsWeightsSet]; @@ -6426,31 +6436,41 @@ TOOL_ERROR Setup_Regions( goto ret; } - /* Find Skipped Regions */ + /* Find Non-Instrumented Regions marked with #ifdef WMC_TOOL_SKIP ... #undef WMC_TOOL_SKIP */ /* Start at Beginning */ ptr = ParseCtx_ptr->File.Data; - /* Find the Beginning of Skipped Regions */ + /* Find the Beginning of Non-Instrumented Regions */ while ( ( ptr = Find_Identifier( ptr, WMC_TOOL_SKIP_STRING, ParseTbl_ptr, ITEM_CSTE_NAME, ITEM_ENCLOSED, &idx ) ) != NULL ) { /* Get Record */ ParseRec_ptr = &ParseTbl_ptr->Data[idx]; + /* Go to Start of Next Line */ ptr = strlend( ParseRec_ptr->item_end ) + 1; - /* Find the End of Skipped Regions */ + + /* Find the End of Non-Instrumented Regions */ /* Found it? */ if ( ( end = Find_Identifier( ptr, WMC_TOOL_SKIP_STRING, ParseTbl_ptr, ITEM_PREPROC_ARGS | ITEM_PREPROC_UNDEF, ITEM_ENCLOSED, &idx ) ) == NULL ) { /* No */ - /* Skipped Regon will End at EOF */ - end = file_ptr->Data + file_ptr->Size; + + /* Error - #undef WMC_TOOL_SKIP missing ! */ + ErrCode = ERR_EXPECTED_EOS; + Error("Unable to find matching #undef %s!", ErrCode, WMC_TOOL_SKIP_STRING); + goto ret; + + /* Skipped Region will End at EOF */ + //end = file_ptr->Data + file_ptr->Size; } else { /* Yes */ /* Go to Preprocessor Command */ idx--; + /* Get Record */ ParseRec_ptr = &ParseTbl_ptr->Data[idx]; - /* Skipped Region will End before #undef */ + + /* Non-Instrumented Region will End before #undef */ end = ParseRec_ptr->item_start; } @@ -6487,8 +6507,10 @@ TOOL_ERROR Setup_Regions( { /* Get Record */ ParseRec_ptr = &ParseTbl_ptr->Data[idx]; + /* Mark Comment as Instrumentation */ ParseRec_ptr->item_type |= ITEM_INSTRUMENTATION; + /* continue After Comment */ ptr = ParseRec_ptr->item_end; } @@ -7223,7 +7245,7 @@ TOOL_ERROR DesInstrument( { /* Yes */ /* Go To Start of Line */ tmp = ParseRec_ptr->item_start; - while ( --tmp, !IS_EOL_CHAR( *tmp ) ) + while ( --tmp, (IS_SPACE_CHAR( *tmp ) && !IS_EOL_CHAR( *tmp )) ) ; /* Advance (Past EOS) */ ptr += 2; @@ -8059,6 +8081,12 @@ TOOL_ERROR Include_Header( /* Find the End of the Last Contiguous Preprocessor Directive Block (#include) */ ptr_end = Find_End_Preproc_Block(NULL, ParseTbl_ptr); + /* if no #include is present in the file set the pointer to the beginning of the file */ + if (ptr_end == NULL) + { + ptr_end = ParseCtx_ptr->File.Data; + } + /* store the pointer for later use */ if (ptr_end_preproc_block != NULL) { @@ -8147,7 +8175,7 @@ TOOL_ERROR Instrument( is_function_present = 1; } - /* Check, if there are const xx[] arrays */ + /* Check, if there are any const xx[] arrays */ is_cnst_data_present = 0; if ((Find_Identifier(ParseCtx_ptr->File.Data, CONST_STRING, ParseTbl_ptr, ITEM_ANY, ITEM_FUNC_DEF | ITEM_NOT_SEARCHED | ITEM_INSTRUMENTATION_OFF)) != NULL) { @@ -8174,10 +8202,13 @@ TOOL_ERROR Instrument( /* Reset Max Function Name Length */ max_name_length = 0; + /* Reset # of Occurances */ max_name_occ = 0; + /* Start at Beginning */ FctCallRec_ptr = FctCallTbl_ptr->Data; + /* Process all Project Function Calls */ for (idx = 0; idx < FctCallTbl_ptr->Size; idx++) { @@ -8185,10 +8216,12 @@ TOOL_ERROR Instrument( name_length = FctCallRec_ptr->NameLength; if (max_name_length < name_length) max_name_length = name_length; + /* Get Max Name Occurances */ name_occ = FctCallRec_ptr->NameOcc; if (max_name_occ < name_occ) max_name_occ = name_occ; + /* Advance */ FctCallRec_ptr++; } @@ -8348,8 +8381,16 @@ TOOL_ERROR Instrument( miscs += name_occ, ParseCtx_ptr->PROMSize += name_occ * prom_ops_weights_ptr->misc; } + /* Find BASOP Functions and Count their PROM size */ + for (idx = 0; (idx = Find_Region(NULL, ParseTbl_ptr, ITEM_CALL | ITEM_FUNC_BASOP, idx)) >= 0; idx++) + { + /* By default it is assumed that all BASOP functions take one PROM word */ + ParseCtx_ptr->PROMSize++; + } + /* Insert PROM_Size_Func() function */ - if (is_function_present) + //if (is_function_present) + if (ParseCtx_ptr->PROMSize > 0) { if ((ErrCode = Instrument_PROM(ParseCtx_ptr)) != NO_ERR) { @@ -8683,14 +8724,14 @@ static void Print_Words( const char *words, bool ds = false, int margin = 4 ) /* Terminate String */ temp[margin + lin_length] = NUL_CHAR; /* Print */ - printf("%s", temp); + fprintf(stdout, "%s", temp); /* Advance */ ptr += lin_length; /* Update Remaining Length */ str_length -= lin_length; } while ( str_length > 0 ); /* Print newline */ - printf( "\n" ); + fprintf(stdout, "\n" ); } } @@ -8701,34 +8742,32 @@ void Print_Information( void ) { int i; - printf( "\n Manual Macros Removed during Desintrumentation:\n" ); + fprintf(stdout, "\n Manual Macros Removed during Desintrumentation:\n" ); Print_Words( MANUAL_COUNTING_MACROS_STRING ); - printf( "\n WMOPS Library Functions that are not Instrumented:\n" ); - Print_Words( WMOPS_COUNTLIB_FUNCTS_STRING, true ); - printf( "\n Other Counting Functions that are not Instrumented:\n" ); - Print_Words( OTHER_COUNTLIB_FUNCTS_STRING ); - printf( "\n WMC_Tool Functions that are not Instrumented:\n" ); - Print_Words( TOOL_FUNCTS_STRING, true ); - printf( "\n System Functions that are not Instrumented:\n" ); + fprintf(stdout, "\n BASOP Functions that are not Instrumented:\n" ); + Print_Words( BASOP_FUNCTS_STRING, true ); + fprintf(stdout, "\n WMOPS Library Functions that are not Instrumented:\n"); + Print_Words(WMOPS_FUNCTS_STRING, true); + fprintf(stdout, "\n System Functions that are not Instrumented:\n" ); Print_Words( SYSTEM_FUNCTS_STRING ); - printf( "\n System Functions that are Instrumented:\n" ); + fprintf(stdout, "\n System Functions that are Instrumented:\n" ); Print_Words( SYSTEM_ALLOC_FUNCTS_STRING ); - printf( "\n Preprocessor Directives that are Ignored:\n" ); + fprintf(stdout, "\n Preprocessor Directives that are Ignored:\n" ); for (i = 0; Conditionnal_Directives[i] != NULL; i++) { - printf(" %c%s\n", PREPROC_CHAR, Conditionnal_Directives[i]); + fprintf(stdout, " %c%s\n", PREPROC_CHAR, Conditionnal_Directives[i]); } - printf( " %c%s\n", PREPROC_CHAR, Undefine_Directive ); + fprintf(stdout, " %c%s\n", PREPROC_CHAR, Undefine_Directive ); for (i = 0; Other_Directives[i] != NULL; i++) { - printf(" %c%s\n", PREPROC_CHAR, Other_Directives[i]); + fprintf(stdout, " %c%s\n", PREPROC_CHAR, Other_Directives[i]); } - printf( "\n Math Functions that are Instrumented:\n" ); + fprintf(stdout, "\n Math Functions that are Instrumented:\n" ); Print_Words( MATH_FUNCTS_STRING ); - printf( "\n Keywords that are Instrumented:\n" ); + fprintf(stdout, "\n Keywords that are Instrumented:\n" ); for ( i = 0; i < (int)(nitems( keywords )); i++ ) { if ( !( keywords[i].kw_type & ITEM_SKIPPED ) ) @@ -8737,7 +8776,7 @@ void Print_Information( void ) } } - printf( "\n Keywords that are not Instrumented:\n" ); + fprintf(stdout, "\n Keywords that are not Instrumented:\n" ); for ( i = 0; i < (int)(nitems( keywords )); i++ ) { if ( keywords[i].kw_type & ITEM_SKIPPED ) @@ -8746,22 +8785,22 @@ void Print_Information( void ) } } - printf( "\n Recognized Data Types:\n" ); + fprintf(stdout, "\n Recognized Data Types:\n" ); Print_Words( TYPES_STRING ); - printf( "\n Macros used to Instrument: \n" ); - printf( " switch/case: %s(n)\n", AUTO_CASE_COUNTING_MACRO_STRING ); - printf( " logical operators: %s\n", LOGICAL_INSTRUMENT_STRING ); - printf( " ternary operators: %s\n", TERNARY_INSTRUMENT_STRING ); - printf( " all other operators: %s(\"ops_string\")\n", AUTO_DEFAULT_COUNTING_MACRO_STRING ); + fprintf(stdout, "\n Macros used to Instrument: \n" ); + fprintf(stdout, " switch/case: %s(n)\n", AUTO_CASE_COUNTING_MACRO_STRING ); + fprintf(stdout, " logical operators: %s\n", LOGICAL_INSTRUMENT_STRING ); + fprintf(stdout, " ternary operators: %s\n", TERNARY_INSTRUMENT_STRING ); + fprintf(stdout, " all other operators: %s(\"ops_string\")\n", AUTO_DEFAULT_COUNTING_MACRO_STRING ); - printf( "\n Include File Required in Instrumented Source Files:\n" ); - printf( " %s\n", WMOPS_LIB_INCLUDE_STRING ); + fprintf(stdout, "\n Include File Required in Instrumented Source Files:\n" ); + fprintf(stdout, " %s\n", WMOPS_LIB_INCLUDE_STRING ); - printf( "\n Skip Instrumentation:\n" ); - printf( " Begin Uninstrumented Segment: #define " WMC_TOOL_SKIP_STRING "\n" ); - printf( " End of Uninstrumented Segment: #undef " WMC_TOOL_SKIP_STRING "\n" ); - printf( "\n" ); + fprintf(stdout, "\n Skip Instrumentation:\n" ); + fprintf(stdout, " Begin Uninstrumented Segment: #define " WMC_TOOL_SKIP_STRING "\n" ); + fprintf(stdout, " End of Uninstrumented Segment: #undef " WMC_TOOL_SKIP_STRING "\n" ); + fprintf(stdout, "\n" ); } /*-------------------------------------------------------------------* diff --git a/src/wmc_tool/c_parser.h b/src/wmc_tool/c_parser.h index db15eaf..fcdf810 100644 --- a/src/wmc_tool/c_parser.h +++ b/src/wmc_tool/c_parser.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file diff --git a/src/wmc_tool/constants.h b/src/wmc_tool/constants.h index d75944b..76812a2 100644 --- a/src/wmc_tool/constants.h +++ b/src/wmc_tool/constants.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -98,7 +98,8 @@ "Encoder_State " #define CONST_STRING "const" #define STORAGE_STRING "extern " \ - "static " CONST_STRING " " + "static " \ + "const " #define DATA_DEF_STRING TYPES_STRING TYPE_MOD_STRING TYPEDEF_STRING STORAGE_STRING diff --git a/src/wmc_tool/mem_analysis.py b/src/wmc_tool/mem_analysis.py new file mode 100644 index 0000000..20b239d --- /dev/null +++ b/src/wmc_tool/mem_analysis.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +# (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. +# +# This software is protected by copyright law and by international treaties. The source code, and all of its derivations, +# is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file +# or refer to ITU-T Recommendation G.191 on "SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS". +# +# Any use of this software is permitted provided that this notice is not removed and that neither the authors nor +# VoiceAge Corporation are deemed to have made any representations as to the suitability of this software +# for any purpose nor are held responsible for any defects of this software. THERE IS NO WARRANTY FOR THIS SOFTWARE. +# +# Authors: Guy Richard, Vladimir Malenovsky (Vladimir.Malenovsky@USherbrooke.ca) + +# This script provides graphical analysis of the memory allocation tree based on the .csv memory output file generated by the WMC tool +# +# usage: python3 mem_analysis.py mem_analysis.csv +# +# where mem_analysis.csv is the per-frame and per-block memory allocation output file generated by the WMC tool +# by activating the MEM_COUNT_DETAILS macro + +import os +import argparse +import csv +import sys +import struct +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + + +# set matplotlib in interactive mode (plots figure and return control) +# plt.ion() +# plt.close('all') + +parser = argparse.ArgumentParser(description='Analyze memory output file') +parser.add_argument('input',type=str,help='Memory analysis file (e.g. mem_analysis.csv)') +args = parser.parse_args() +fileIn = args.input + +# read input .csv file +df = pd.read_csv(fileIn, header=None, names=['action_type', 'frame', 'name', 'line_no', 'mem_size']) +Nframes = max(df['frame']) + +# merge identical memory blocks -> create new column 'count' +df = df.groupby(df.columns.tolist(),as_index=False).size() +df = df.rename(columns={'size': 'count'}) + +# remove column 'action_type' +df.drop(columns = ['action_type']) + +# merge records with the same signature but different frame number -> create list of frames (sort in ascending order) +df = df.groupby(['name', 'line_no', 'mem_size', 'count'],as_index=False).agg({'frame': list}) +df['frame'] = df['frame'].apply(np.sort) +df['list_len'] = df['frame'].apply(len) # auxiliary column -> length of the list + +# merge records with the same name and frame but different line number -> sum memory sizes and counts +df = df.groupby(['name', 'list_len'],as_index=False).agg({'line_no': list, 'mem_size': sum, 'count':sum, 'frame':'first'}) + +# sort by memory size (put inter-frame memory blocks to the bottom) +select_inter = (df['list_len'] == 2) & (df.apply(lambda row : row['frame'][-1] - row['frame'][0], axis = 1) >= Nframes) +df_inter = df[select_inter] +df_inter = df_inter.sort_values(by=['mem_size'], ascending=False) +df_intra = df[~select_inter] +df_intra = df_intra.sort_values(by=['list_len'], ascending=True) + +# plot inter-frame memory blocks in horizontal bar graph (use .broken_barh method) +fig, ax = plt.subplots() +colors = iter(plt.cm.rainbow(np.linspace(0, 1, len(df.index)))) +y_ticks = [] +y_tick_labels = [] +y_low = 1 +for index, row in df_inter.iterrows(): + l = f"{row['name']} on lines: {row['line_no']}, total memory size: {row['count']}x{row['mem_size']}" + fms = row['frame'].reshape((-1,2)) # convert frame numbers to two-column format + fms[:,1] -= fms[:,0] # second column should now represent the duration of the segment + fmsT = fms.T + fms_list = list(zip(fmsT[0], fmsT[1])) + c = next(colors) + ax.broken_barh(xranges=fms_list, yrange=(y_low, row['count']), label=l, color=c) + y_ticks.append(y_low + 0.5 * row['count']) + y_tick_labels.append(row['name']) + y_low += row['count'] + 0.5 + print(l + f", {row['count'] * fms.shape[0]/Nframes:.3f} mallocs per frame") + +# plot intra-frame memory blocks in horizontal bar graph (use .broken_barh method) +df_intra = df_intra.groupby(['name'],as_index=False).agg({'list_len': list, 'line_no': list, 'mem_size': list, 'count': list, 'frame': list}) +for index, row in df_intra.iterrows(): + # repeat for all grouped memory records in the row + for j in range(len(row['list_len'])): + l = f"{row['name']} on lines: {row['line_no'][j]}, total memory size: {row['count'][j]}x{row['mem_size'][j]}" + fms = row['frame'][j].astype(float).reshape((-1,2)) # convert frame numbers to two-column format + fms[:,1] -= fms[:,0] # second column should now represent the duration of the segment + idx_zero = fms[:,1] == 0 # find zero-length segments -> these are intra-frame memory blocks + fms[idx_zero, 0] += 0.1 + fms[idx_zero, 1] = 0.8 + fmsT = fms.T + fms_list = list(zip(fmsT[0], fmsT[1])) + c = next(colors) + ax.broken_barh(xranges=fms_list, yrange=(y_low, row['count'][j]), label=l, color=c, alpha=0.6) + print(l + f", {row['count'][j] * fms.shape[0]/Nframes:.3f} mallocs per frame") + y_ticks.append(y_low + 0.5 * max(row['count'])) + y_tick_labels.append(row['name']) + y_low += max(row['count']) + 0.5 + +ax.set_yticks(y_ticks) +ax.set_yticklabels(y_tick_labels) +ax.set_ylabel('Memory size') +ax.set_xlabel('Frame') +ax.set_title('Memory analysis') + +# shrink current axis's height by 20% on the bottom to fit the legend +box = ax.get_position() +ax.set_position([box.x0, box.y0 + box.height * 0.2, box.width, box.height * 0.8]) + +# insert the legend below the graph +ax.legend(loc="upper left", bbox_to_anchor=(0, -0.1), ncol=2, borderaxespad=0, fontsize='small') + +# magnify to "almost" fullscreen size (select the alternative for your backend) +fig = plt.gcf() +fig.set_size_inches(15, 9) # we need to set the size manually, otherwise savefig will save the figure in the default size +mng = plt.get_current_fig_manager() +mng.full_screen_toggle() +# mng.frame.Maximize(True) +# mng.window.showMaximized() +# mng.window.state('zoomed') + +# show and save the figure (use block=True to wait until Figure is closed manually) +plt.savefig(os.path.splitext(args.input)[0] + '.png', dpi=100, bbox_inches='tight') +plt.show(block=True) diff --git a/src/wmc_tool/output.cpp b/src/wmc_tool/output.cpp index 685b905..ba43b4b 100644 --- a/src/wmc_tool/output.cpp +++ b/src/wmc_tool/output.cpp @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file diff --git a/src/wmc_tool/output.h b/src/wmc_tool/output.h index 34ba4db..015dfd0 100644 --- a/src/wmc_tool/output.h +++ b/src/wmc_tool/output.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file diff --git a/src/wmc_tool/parsing_defs.h b/src/wmc_tool/parsing_defs.h index d2863b2..9994914 100644 --- a/src/wmc_tool/parsing_defs.h +++ b/src/wmc_tool/parsing_defs.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -188,6 +188,7 @@ #define ITEM_FUNC_COUNTERS_MAN 0x01 #define ITEM_FUNC_COUNTERS ( ITEM_FUNC_COUNTERS_MAN | ITEM_FUNC_COUNTERS_AUTO ) #define ITEM_FUNC_COUNT_LIB 0x20 +#define ITEM_FUNC_BASOP 0x10 #define ITEM_FUNC_SYSTEM 0x40 /* Attributes for ITEM_SKIPPED */ diff --git a/src/wmc_tool/requirements.txt b/src/wmc_tool/requirements.txt new file mode 100644 index 0000000..510bec3 --- /dev/null +++ b/src/wmc_tool/requirements.txt @@ -0,0 +1,3 @@ +matplotlib>=3.8 +numpy>=1.26 +pandas>=2.2 diff --git a/src/wmc_tool/test_data/ref/main1.c b/src/wmc_tool/test_data/ref/main1.c index e7753d1..45657cd 100644 --- a/src/wmc_tool/test_data/ref/main1.c +++ b/src/wmc_tool/test_data/ref/main1.c @@ -65,3 +65,5 @@ int main( #endif return 0; } + +#undef WMC_TOOL_SKIP \ No newline at end of file diff --git a/src/wmc_tool/test_data/ref/main2.c b/src/wmc_tool/test_data/ref/main2.c index 2412264..e77f327 100644 --- a/src/wmc_tool/test_data/ref/main2.c +++ b/src/wmc_tool/test_data/ref/main2.c @@ -20,7 +20,7 @@ /*AddedByWMC_Tool*/} /*AddedByWMC_Tool*/ROM_Size_Lookup_Table Const_Data_PROM_Table[] = /*AddedByWMC_Tool*/{ -/*AddedByWMC_Tool*/ { "out/test*.c", 734, Get_Const_Data_Size_out_test_c }, +/*AddedByWMC_Tool*/ { "out/test*.c", 291, Get_Const_Data_Size_out_test_c }, /*AddedByWMC_Tool*/ { "", -1, NULL } /*AddedByWMC_Tool*/}; /*AddedByWMC_Tool*/#endif diff --git a/src/wmc_tool/test_data/ref/test_basop.c b/src/wmc_tool/test_data/ref/test_basop.c index a3eef18..dd20ac3 100644 --- a/src/wmc_tool/test_data/ref/test_basop.c +++ b/src/wmc_tool/test_data/ref/test_basop.c @@ -53,3 +53,6 @@ void weight_coef_a( const Word16 *a, Word16 *b, const Word16 ght ) return; } + +#undef WMC_TOOL_SKIP +/*AddedByWMC_Tool*/ int PROM_Size_Func( test_basop ) { return 15; } diff --git a/src/wmc_tool/test_data/ref/test_basop32.c b/src/wmc_tool/test_data/ref/test_basop32.c index 8a6875d..9fcdf1e 100644 --- a/src/wmc_tool/test_data/ref/test_basop32.c +++ b/src/wmc_tool/test_data/ref/test_basop32.c @@ -2427,5 +2427,7 @@ Word32 L_msu0 (Word32 L_var3, Word16 var1, Word16 var2) { return (L_var_out); } +#undef WMC_TOOL_SKIP /* end of file */ +/*AddedByWMC_Tool*/ int PROM_Size_Func( test_basop32 ) { return 157; } diff --git a/src/wmc_tool/test_data/ref/wmc_auto.c b/src/wmc_tool/test_data/ref/wmc_auto.c index 69cf37a..7dfcf8b 100644 --- a/src/wmc_tool/test_data/ref/wmc_auto.c +++ b/src/wmc_tool/test_data/ref/wmc_auto.c @@ -25,9 +25,9 @@ #include #endif +#include "options.h" #include "wmc_auto.h" - #define WMC_TOOL_SKIP /* Skip the instrumentation of this file, if invoked by accident */ #ifdef WMOPS @@ -36,23 +36,28 @@ * Complexity counting tool *--------------------------------------------------------------------*/ -#define MAX_RECORDS 1024 -#define MAX_CHAR 64 -#define MAX_STACK 64 -#define DOUBLE_MAX 0x80000000 +#define MAX_FUNCTION_NAME_LENGTH 50 /* Maximum length of the function name */ +#define MAX_PARAMS_LENGTH 50 /* Maximum length of the function parameter string */ +#define MAX_NUM_RECORDS 300 /* Initial maximum number of records -> mightb be increased during runtime, if needed */ +#define MAX_NUM_RECORDS_REALLOC_STEP 50 /* When re-allocating the list of records, increase the number of records by this number */ +#define MAX_CALL_TREE_DEPTH 100 /* maximum depth of the function call tree */ +#define DOUBLE_MAX 0x80000000 +#define FAC ( FRAMES_PER_SECOND / 1e6 ) + -struct wmops_record +typedef struct { - char label[MAX_CHAR]; + char label[MAX_FUNCTION_NAME_LENGTH]; long call_number; long update_cnt; - int call_tree[MAX_RECORDS]; + int call_tree[MAX_CALL_TREE_DEPTH]; + long LastWOper; double start_selfcnt; double current_selfcnt; double max_selfcnt; double min_selfcnt; double tot_selfcnt; - double start_cnt; /* The following take into account the decendants */ + double start_cnt; double current_cnt; double max_cnt; double min_cnt; @@ -63,16 +68,14 @@ struct wmops_record double wc_selfcnt; int32_t wc_call_number; #endif -}; +} wmops_record; double ops_cnt; double prom_cnt; double inst_cnt[NUM_INST]; -static struct wmops_record wmops[MAX_RECORDS]; -static int stack[MAX_STACK]; -static int sptr; -static int num_records; +static wmops_record *wmops = NULL; +static int num_wmops_records, max_num_wmops_records; static int current_record; static long update_cnt; static double start_cnt; @@ -80,20 +83,56 @@ static double max_cnt; static double min_cnt; static double inst_cnt_wc[NUM_INST]; static long fnum_cnt_wc; - +static int *wmops_caller_stack = NULL, wmops_caller_stack_index, max_wmops_caller_stack_index = 0; static int *heap_allocation_call_tree = NULL, heap_allocation_call_tree_size = 0, heap_allocation_call_tree_max_size = 0; - void reset_wmops( void ) { int i, j; + unsigned int *ptr; + + num_wmops_records = 0; + max_num_wmops_records = MAX_NUM_RECORDS; + current_record = -1; + update_cnt = 0; + + max_cnt = 0.0; + min_cnt = DOUBLE_MAX; + start_cnt = 0.0; + ops_cnt = 0.0; + + /* allocate the list of wmops records */ + if ( wmops == NULL ) + { + wmops = (wmops_record *)malloc( max_num_wmops_records * sizeof( wmops_record ) ); + } + + if ( wmops == NULL ) + { + fprintf( stderr, "Error: Unable to Allocate List of WMOPS Records!" ); + exit( -1 ); + } - for ( i = 0; i < MAX_RECORDS; i++ ) + /* allocate the BASOP WMOPS counter */ + if ( multiCounter == NULL ) + { + multiCounter = (BASIC_OP *) malloc( max_num_wmops_records * sizeof( BASIC_OP ) ); + } + + if ( multiCounter == NULL ) + { + fprintf( stderr, "Error: Unable to Allocate the BASOP WMOPS counter!" ); + exit( -1 ); + } + + /* initilize the list of wmops records */ + /* initilize the BASOP WMOPS counters */ + for ( i = 0; i < max_num_wmops_records; i++ ) { strcpy( &wmops[i].label[0], "\0" ); wmops[i].call_number = 0; wmops[i].update_cnt = 0; - for ( j = 0; j < MAX_RECORDS; j++ ) + for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ ) { wmops[i].call_tree[j] = -1; } @@ -111,22 +150,42 @@ void reset_wmops( void ) wmops[i].wc_cnt = 0.0; wmops[i].wc_selfcnt = 0.0; wmops[i].current_call_number = 0; + wmops[i].wc_call_number = -1; #endif + + /* clear all BASOP operation counters */ + ptr = (unsigned int*) &multiCounter[i]; + for ( j = 0; j < (int) ( sizeof(BASIC_OP ) / sizeof( unsigned int ) ); j++ ) + { + *ptr++ = 0; + } + wmops[i].LastWOper = 0; } - for ( i = 0; i < MAX_STACK; i++ ) + /* allocate the list of wmops callers to track the sequence of function calls */ + wmops_caller_stack_index = 0; + max_wmops_caller_stack_index = MAX_NUM_RECORDS; + if ( wmops_caller_stack == NULL ) { - stack[i] = -1; + wmops_caller_stack = malloc( max_wmops_caller_stack_index * sizeof( int ) ); } - sptr = 0; - num_records = 0; - current_record = -1; - update_cnt = 0; - max_cnt = 0.0; - min_cnt = DOUBLE_MAX; - start_cnt = 0.0; - ops_cnt = 0.0; + if ( wmops_caller_stack == NULL ) + { + fprintf( stderr, "Error: Unable to Allocate List of WMOPS Callers!" ); + exit( -1 ); + } + + for ( i = 0; i < max_wmops_caller_stack_index; i++ ) + { + wmops_caller_stack[i] = -1; + } + + /* initialize auxiliary BASOP WMOPS variables */ + call_occurred = 1; + funcId_where_last_call_to_else_occurred = INT_MAX; + + return; } @@ -135,9 +194,9 @@ void push_wmops( const char *label ) int new_flag; int i, j; - /* Check if new function record label */ + /* Check, if this is a new function label */ new_flag = 1; - for ( i = 0; i < num_records; i++ ) + for ( i = 0; i < num_wmops_records; i++ ) { if ( strcmp( wmops[i].label, label ) == 0 ) { @@ -146,33 +205,38 @@ void push_wmops( const char *label ) } } - /* Configure new record */ + /* Create a new record in the list */ if ( new_flag ) { - if ( num_records >= MAX_RECORDS ) + if ( num_wmops_records >= max_num_wmops_records ) { - fprintf( stdout, "push_wmops(): exceeded MAX_RECORDS count.\n\n" ); - exit( -1 ); + /* There is no room for a new wmops record -> reallocate the list */ + max_num_wmops_records += MAX_NUM_RECORDS_REALLOC_STEP; + wmops = realloc( wmops, max_num_wmops_records * sizeof( wmops_record ) ); + multiCounter = realloc( multiCounter, max_num_wmops_records * sizeof( BASIC_OP ) ); } + strcpy( wmops[i].label, label ); - num_records++; + + num_wmops_records++; } - /* Push current context onto stack */ + /* Push the current context info to the new record */ if ( current_record >= 0 ) { - if ( sptr >= MAX_STACK ) + if ( wmops_caller_stack_index >= max_wmops_caller_stack_index ) { - fprintf( stdout, "\r push_wmops(): stack exceeded, try inreasing MAX_STACK\n" ); - exit( -1 ); + /* There is no room for a new record -> reallocate the list */ + max_wmops_caller_stack_index += MAX_NUM_RECORDS_REALLOC_STEP; + wmops_caller_stack = realloc( wmops_caller_stack, max_wmops_caller_stack_index * sizeof( int ) ); } - stack[sptr++] = current_record; + wmops_caller_stack[wmops_caller_stack_index++] = current_record; /* accumulate op counts */ wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt; /* update call tree */ - for ( j = 0; j < MAX_RECORDS; j++ ) + for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ ) { if ( wmops[i].call_tree[j] == current_record ) { @@ -186,7 +250,7 @@ void push_wmops( const char *label ) } } - /* init current record */ + /* update the current context info */ current_record = i; wmops[current_record].start_selfcnt = ops_cnt; wmops[current_record].start_cnt = ops_cnt; @@ -195,12 +259,16 @@ void push_wmops( const char *label ) wmops[current_record].current_call_number++; #endif + /* set the ID of BASOP functions counters */ + Set_BASOP_WMOPS_counter( current_record ); + return; } void pop_wmops( void ) { + long tot; /* Check for underflow */ if ( current_record < 0 ) @@ -209,21 +277,29 @@ void pop_wmops( void ) exit( -1 ); } - /* update count of current record */ + /* add the BASOP complexity to the counter */ + tot = DeltaWeightedOperation(); + ops_cnt += tot; + + /* update count of current record */ wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt; wmops[current_record].current_cnt += ops_cnt - wmops[current_record].start_cnt; /* Get back previous context from stack */ - if ( sptr > 0 ) + if ( wmops_caller_stack_index > 0 ) { - current_record = stack[--sptr]; + current_record = wmops_caller_stack[--wmops_caller_stack_index]; wmops[current_record].start_selfcnt = ops_cnt; + + /* set the ID of the previous BASOP counter */ + Set_BASOP_WMOPS_counter( current_record ); } else { current_record = -1; } + return; } @@ -238,9 +314,9 @@ void update_wmops( void ) float tmpF; #endif - if ( sptr != 0 ) + if ( wmops_caller_stack_index != 0 ) { - fprintf( stdout, "update_wmops(): Stack must be empty!\n" ); + fprintf( stdout, "update_wmops(): WMOPS caller stack corrupted - check that all push_wmops() are matched with pop_wmops()!\n" ); exit( -1 ); } @@ -265,7 +341,7 @@ void update_wmops( void ) #ifdef WMOPS_WC_FRAME_ANALYSIS if ( ops_cnt - start_cnt > max_cnt ) { - for ( i = 0; i < num_records; i++ ) + for ( i = 0; i < num_wmops_records; i++ ) { wmops[i].wc_cnt = wmops[i].current_cnt; wmops[i].wc_selfcnt = wmops[i].current_selfcnt; @@ -274,7 +350,7 @@ void update_wmops( void ) } #endif - for ( i = 0; i < num_records; i++ ) + for ( i = 0; i < num_wmops_records; i++ ) { wmops[i].tot_selfcnt += wmops[i].current_selfcnt; wmops[i].tot_cnt += wmops[i].current_cnt; @@ -301,6 +377,7 @@ void update_wmops( void ) wmops[i].max_cnt = wmops[i].current_cnt; } + if ( wmops[i].current_cnt < wmops[i].min_cnt ) { wmops[i].min_cnt = wmops[i].current_cnt; @@ -313,6 +390,10 @@ void update_wmops( void ) #ifdef WMOPS_WC_FRAME_ANALYSIS wmops[i].current_call_number = 0; #endif + + /* update the WC of all BASOP counters */ + Set_BASOP_WMOPS_counter( i ); + Reset_BASOP_WMOPS_counter(); } current_cnt = ops_cnt - start_cnt; @@ -340,12 +421,6 @@ void update_wmops( void ) start_cnt = ops_cnt; - if ( heap_allocation_call_tree_size > 0 ) - { - /* update intra-frame heap memory and inter-frame heap memory*/ - update_mem(); - } - /* increment frame counter */ update_cnt++; @@ -355,28 +430,40 @@ void update_wmops( void ) void print_wmops( void ) { - int i; + int i, label_len, max_label_len; - char *sfmts = "%20s %8s %8s %7s %7s\n"; - char *dfmts = "%20s %8.2f %8.3f %7.3f %7.3f\n"; - char *sfmt = "%20s %8s %8s %7s %7s %7s %7s %7s\n"; - char *dfmt = "%20s %8.2f %8.3f %7.3f %7.3f %7.3f %7.3f %7.3f\n"; + char *sfmts = "%*s %8s %8s %7s %7s\n"; + char *dfmts = "%*s %8.2f %8.3f %7.3f %7.3f\n"; + char *sfmt = "%*s %8s %8s %7s %7s %7s %7s %7s\n"; + char *dfmt = "%*s %8.2f %8.3f %7.3f %7.3f %7.3f %7.3f %7.3f\n"; #ifdef WMOPS_WC_FRAME_ANALYSIS - int j, label_len, max_label_len; + int j; char *sfmtt = "%20s %4s %15s\n"; char *dfmtt = "%20s %4d "; #endif - fprintf( stdout, "\n\n --- Complexity analysis [WMOPS] --- \n\n" ); + /* calculate maximum label length for compact prinout */ + max_label_len = 0; + for ( i = 0; i < num_wmops_records; i++ ) + { + label_len = strlen( wmops[i].label ); + if ( label_len > max_label_len ) + { + max_label_len = label_len; + } + } + max_label_len += 4; - fprintf( stdout, "%54s %23s\n", "|------ SELF ------|", "|--- CUMULATIVE ---|" ); - fprintf( stdout, sfmt, " routine", " calls", " min ", " max ", " avg ", " min ", " max ", " avg " ); - fprintf( stdout, sfmt, "---------------", "------", "------", "------", "------", "------", "------", "------" ); + fprintf( stdout, "\n\n --- Complexity analysis [WMOPS] --- \n\n" ); + + fprintf( stdout, "%*s %33s %23s\n", max_label_len, "", "|------ SELF ------|", "|--- CUMULATIVE ---|" ); + fprintf( stdout, sfmt, max_label_len, " routine", " calls", " min ", " max ", " avg ", " min ", " max ", " avg " ); + fprintf( stdout, sfmt, max_label_len, "---------------", "------", "------", "------", "------", "------", "------", "------" ); - for ( i = 0; i < num_records; i++ ) + for ( i = 0; i < num_wmops_records; i++ ) { - fprintf( stdout, dfmt, wmops[i].label, update_cnt == 0 ? 0 : (float) wmops[i].call_number / update_cnt, + fprintf( stdout, dfmt, max_label_len, wmops[i].label, update_cnt == 0 ? 0 : (float) wmops[i].call_number / update_cnt, wmops[i].min_selfcnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_selfcnt, FAC * wmops[i].max_selfcnt, wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_selfcnt / wmops[i].update_cnt, @@ -385,54 +472,47 @@ void print_wmops( void ) wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_cnt / wmops[i].update_cnt ); } - fprintf( stdout, sfmts, "---------------", "------", "------", "------", "------" ); - fprintf( stdout, dfmts, "total", (float) update_cnt, FAC * min_cnt, FAC * max_cnt, update_cnt == 0 ? 0 : FAC * ops_cnt / update_cnt ); + fprintf( stdout, sfmts, max_label_len, "---------------", "------", "------", "------", "------" ); + fprintf( stdout, dfmts, max_label_len, "total", (float) update_cnt, update_cnt == 0 ? 0 : FAC * min_cnt, FAC * max_cnt, update_cnt == 0 ? 0 : FAC * ops_cnt / update_cnt ); fprintf( stdout, "\n" ); #ifdef WMOPS_WC_FRAME_ANALYSIS - /* calculate maximum label length for compact prinout */ - max_label_len = 0; - for ( i = 0; i < num_records; i++ ) - { - label_len = strlen( wmops[i].label ); - if ( label_len > max_label_len ) - { - max_label_len = label_len; - } - } - max_label_len += 4; - - fprintf( stdout, "\nComplexity analysis for the worst-case frame %ld:\n", fnum_cnt_wc ); - fprintf( stdout, "%*s %8s %10s %12s\n", max_label_len, " routine", " calls", " SELF", " CUMULATIVE" ); + fprintf( stdout, "\nComplexity analysis for the worst-case frame %ld:\n\n", fnum_cnt_wc ); + fprintf( stdout, "%*s %8s %10s %12s\n", max_label_len, " routine", " calls", " SELF", " CUMULATIVE" ); fprintf( stdout, "%*s %8s %10s %10s\n", max_label_len, "---------------", "------", "------", "----------" ); - for ( i = 0; i < num_records; i++ ) + for ( i = 0; i < num_wmops_records; i++ ) { - fprintf( stdout, "%*s %8d %10.3f %12.3f\n", max_label_len, wmops[i].label, wmops[i].wc_call_number, FAC * wmops[i].wc_selfcnt, FAC * wmops[i].wc_cnt ); + if ( wmops[i].wc_call_number > 0 ) + { + fprintf( stdout, "%*s %8d %10.3f %12.3f\n", max_label_len, wmops[i].label, wmops[i].wc_call_number, FAC * wmops[i].wc_selfcnt, FAC * wmops[i].wc_cnt ); + } } - fprintf( stdout, "\nCall Tree:\n\n" ); - fprintf( stdout, sfmtt, " function", "num", "called by: " ); + fprintf( stdout, "\nCall tree for the worst-case frame %ld:\n\n", fnum_cnt_wc ); + fprintf( stdout, sfmtt, " function", "num", "called by " ); fprintf( stdout, sfmtt, "---------------", "---", "--------------" ); - for ( i = 0; i < num_records; i++ ) + for ( i = 0; i < num_wmops_records; i++ ) { - fprintf( stdout, dfmtt, wmops[i].label, i ); - for ( j = 0; wmops[i].call_tree[j] != -1; j++ ) + if ( wmops[i].wc_call_number > 0 ) { - if ( j != 0 ) + fprintf( stdout, dfmtt, wmops[i].label, i ); + for ( j = 0; wmops[i].call_tree[j] != -1 && j < MAX_CALL_TREE_DEPTH; j++ ) { - fprintf( stdout, ", " ); + if ( j != 0 ) + { + fprintf( stdout, ", " ); + } + fprintf( stdout, "%d", wmops[i].call_tree[j] ); } - fprintf( stdout, "%d", wmops[i].call_tree[j] ); + fprintf( stdout, "\n" ); } - fprintf( stdout, "\n" ); } - fprintf( stdout, sfmtt, "---------------", "---", "--------------" ); fprintf( stdout, "\n\n" ); - fprintf( stdout, "\nInstruction type analysis for the worst-case frame %ld:\n\n", fnum_cnt_wc ); /* added -- JPA */ + fprintf( stdout, "\nInstruction type analysis for the worst-case frame %ld:\n\n", fnum_cnt_wc ); for ( i = 0; i < NUM_INST; i++ ) { switch ( (enum instructions) i ) @@ -503,6 +583,24 @@ void print_wmops( void ) } #endif + /* De-allocate the list of wmops record */ + if ( wmops != NULL ) + { + free( wmops ); + } + + /* De-allocate the list of wmops caller functions */ + if ( wmops_caller_stack != NULL ) + { + free( wmops_caller_stack ); + } + + /* De-allocate the BASOP WMOPS counter */ + if ( multiCounter != NULL ) + { + free( multiCounter ); + } + return; } @@ -529,12 +627,6 @@ void print_wmops( void ) * #define WMC_TOOL_SKIP ... #undef WMC_TOOL_SKIP macro pair around the malloc(), calloc() and free(). *--------------------------------------------------------------------*/ -#define MAX_RECORDABLE_CALLS 100 -#define MAX_FUNCTION_NAME_LENGTH 35 /* Maximum length that the function string will be truncated to */ -#define MAX_PARAMS_LENGTH 50 /* Maximum length that the parameter string will be truncated to */ -#define MAX_NUM_RECORDS 300 /* Initial maximum number of memory records -> mightb be increased during runtime, if needed */ -#define MAX_NUM_RECORDS_REALLOC_STEP 50 /* When re-allocating the list of memory records, increase the number of records by this number */ - /* This is the value (in bytes) towards which the block size is rounded. For example, a block of 123 bytes, when using a 32 bits system, will end up taking 124 bytes since the last unused byte cannot be used for another block. */ #ifdef MEM_ALIGN_64BITS @@ -544,14 +636,17 @@ void print_wmops( void ) #endif #define N_32BITS_BLOCKS ( BLOCK_ROUNDING / sizeof( int32_t ) ) +#define ROUND_BLOCK_SIZE( n ) ( ( ( n ) + BLOCK_ROUNDING - 1 ) & ~( BLOCK_ROUNDING - 1 ) ) #define MAGIC_VALUE_OOB 0x12A534F0 /* Signature value which is inserted before and after each allocated memory block, used to detect out-of-bound access */ #define MAGIC_VALUE_USED ( ~MAGIC_VALUE_OOB ) /* Value used to pre-fill allocated memory blocks, used to calculate actual memory usage */ #define OOB_START 0x1 /* Flag indicating out-of-bounds access before memory block */ #define OOB_END 0x2 /* Flag indicating out-of-bounds access after memory block */ -#define ROUND_BLOCK_SIZE( n ) ( ( ( n ) + BLOCK_ROUNDING - 1 ) & ~( BLOCK_ROUNDING - 1 ) ) -#define IS_CALLOC( str ) ( str[0] == 'c' ) +#ifdef MEM_COUNT_DETAILS +const char *csv_filename = "mem_analysis.csv"; +static FILE *fid_csv_filename = NULL; +#endif typedef struct { @@ -559,8 +654,16 @@ typedef struct int16_t *stack_ptr; } caller_info; -caller_info stack_callers[2][MAX_RECORDABLE_CALLS]; +static caller_info *stack_callers[2] = {NULL, NULL}; +static int16_t *ptr_base_stack = 0; /* Pointer to the bottom of stack (base pointer). Stack grows up. */ +static int16_t *ptr_current_stack = 0; /* Pointer to the current stack pointer */ +static int16_t *ptr_max_stack = 0; /* Pointer to the maximum stack pointer (the farest point from the bottom of stack) */ +static int32_t wc_stack_frame = 0; /* Frame corresponding to the worst-case stack usage */ +static int current_calls = 0, max_num_calls = MAX_NUM_RECORDS; +static char location_max_stack[256] = "undefined"; + +/* Heap-related variables */ typedef struct { char name[MAX_FUNCTION_NAME_LENGTH + 1]; /* +1 for NUL */ @@ -580,18 +683,12 @@ typedef struct allocator_record *allocation_list = NULL; -static int16_t *ptr_base_stack = 0; /* Pointer to the bottom of stack (base pointer). Stack grows up. */ -static int16_t *ptr_current_stack = 0; /* Pointer to the current stack pointer */ -static int16_t *ptr_max_stack = 0; /* Pointer to the maximum stack pointer (the farest point from the bottom of stack) */ -static int32_t wc_stack_frame = 0; /* Frame corresponding to the worst-case stack usage */ -static int32_t wc_ram_size, wc_ram_frame; -static int32_t current_heap_size; -static int current_calls = 0; -static char location_max_stack[256] = "undefined"; static int Num_Records, Max_Num_Records; static size_t Stat_Cnt_Size = USE_BYTES; -static const char *Count_Unit[] = { "bytes", "words", "words" }; +static const char *Count_Unit[] = { "bytes", "words", "words", "words" }; +static int32_t wc_ram_size, wc_ram_frame; +static int32_t current_heap_size; static int *list_wc_intra_frame_heap, n_items_wc_intra_frame_heap, max_items_wc_intra_frame_heap, size_wc_intra_frame_heap, location_wc_intra_frame_heap; static int *list_current_inter_frame_heap, n_items_current_inter_frame_heap, max_items_current_inter_frame_heap, size_current_inter_frame_heap; static int *list_wc_inter_frame_heap, n_items_wc_inter_frame_heap, max_items_wc_inter_frame_heap, size_wc_inter_frame_heap, location_wc_inter_frame_heap; @@ -612,11 +709,28 @@ void reset_mem( Counting_Size cnt_size ) int16_t something; size_t tmp_size; + /* initialize list of stack records */ + if ( stack_callers[0] == NULL ) + { + stack_callers[0] = malloc( MAX_NUM_RECORDS * sizeof( caller_info ) ); + stack_callers[1] = malloc( MAX_NUM_RECORDS * sizeof( caller_info ) ); + } + + if ( stack_callers[0] == NULL || stack_callers[1] == NULL ) + { + fprintf( stderr, "Error: Unable to Allocate List of Stack Records!" ); + exit( -1 ); + } + + current_calls = 0; + max_num_calls = MAX_NUM_RECORDS; + /* initialize stack pointers */ ptr_base_stack = &something; ptr_max_stack = ptr_base_stack; ptr_current_stack = ptr_base_stack; + /* initialize the unit of memory block size */ Stat_Cnt_Size = cnt_size; /* Check, if sizeof(int32_t) is 4 bytes */ @@ -687,6 +801,25 @@ void reset_mem( Counting_Size cnt_size ) size_wc_inter_frame_heap = 0; location_wc_inter_frame_heap = -1; +#ifdef MEM_COUNT_DETAILS + /* Check, if the .csv file has already been opened */ + if ( fid_csv_filename == NULL ) + { + fid_csv_filename = fopen( csv_filename, "wb" ); + + if ( fid_csv_filename == NULL ) + { + fprintf( stderr, "\nCannot open %s!\n\n", csv_filename ); + exit( -1 ); + } + } + else + { + /* reset file */ + rewind( fid_csv_filename ); + } +#endif + return; } @@ -723,11 +856,12 @@ int push_stack( const char *filename, const char *fctname ) (void) *filename; /* to avoid compilation warning */ - /* Is there room to save the caller's information? */ - if ( current_calls >= MAX_RECORDABLE_CALLS ) - { /* No */ - fprintf( stderr, "No more room to store call stack info. Please increase MAX_RECORDABLE_CALLS" ); - exit( -1 ); + if ( current_calls >= max_num_calls ) + { + /* There is no room for a new record -> reallocate the list */ + max_num_calls += MAX_NUM_RECORDS_REALLOC_STEP; + stack_callers[0] = realloc( stack_callers[0], max_num_calls * sizeof( caller_info ) ); + stack_callers[1] = realloc( stack_callers[1], max_num_calls * sizeof( caller_info ) ); } /* Valid Function Name? */ @@ -744,7 +878,7 @@ int push_stack( const char *filename, const char *fctname ) /* Save the Stack Pointer */ stack_callers[0][current_calls].stack_ptr = ptr_current_stack; - /* Increase Stack Calling Tree Level */ + /* Increase the Number of Calls in the List */ current_calls++; /* Is this the First Time or the Worst Case? */ @@ -753,15 +887,17 @@ int push_stack( const char *filename, const char *fctname ) /* Save Info about it */ ptr_max_stack = ptr_current_stack; - wc_stack_frame = update_cnt; /* current frame number is stored in the variable update_cnt and updated in the function update_wmops() */ + /* save the worst-case frame number */ + /* current frame number is stored in the variable update_cnt and updated in the function update_wmops() */ + wc_stack_frame = update_cnt; strncpy( location_max_stack, fctname, sizeof( location_max_stack ) - 1 ); location_max_stack[sizeof( location_max_stack ) - 1] = '\0'; /* Save Call Tree */ memmove( stack_callers[1], stack_callers[0], sizeof( caller_info ) * current_calls ); - /* Terminate the List (Unless Full) */ - if ( current_calls < MAX_RECORDABLE_CALLS ) + /* Terminate the List with 0 (for printing purposes) */ + if ( current_calls < max_num_calls ) { stack_callers[1][current_calls].function_name[0] = 0; } @@ -797,13 +933,13 @@ int pop_stack( const char *filename, const char *fctname ) (void) *filename; /* to avoid compilation warning */ - /* Decrease Stack Calling */ + /* Decrease the Number of Records */ current_calls--; /* Get Pointer to Caller Information */ caller_info_ptr = &stack_callers[0][current_calls]; - /* Check, if Names Match */ + /* Check, if the Function Names Match */ if ( strncmp( caller_info_ptr->function_name, fctname, MAX_FUNCTION_NAME_LENGTH ) != 0 ) { fprintf( stderr, "Invalid usage of pop_stack()" ); @@ -842,7 +978,7 @@ static void print_stack_call_tree( void ) fprintf( stdout, "\nList of functions when maximum stack size is reached:\n\n" ); caller_info_ptr = &stack_callers[1][0]; - for ( call_level = 0; call_level < MAX_RECORDABLE_CALLS; call_level++ ) + for ( call_level = 0; call_level < max_num_calls; call_level++ ) { /* Done? */ if ( caller_info_ptr->function_name[0] == 0 ) @@ -959,6 +1095,11 @@ void *mem_alloc( ptr_record->block_size = size; ptr_record->total_block_size += size; +#ifdef MEM_COUNT_DETAILS + /* Export heap memory allocation record to the .csv file */ + fprintf( fid_csv_filename, "A,%d,%s,%d,%d\n", update_cnt, ptr_record->name, ptr_record->lineno, ptr_record->block_size ); +#endif + if ( ptr_record->frame_allocated != -1 ) { fprintf( stderr, "Fct=%s, Ln=%i: %s!\n", func_name, func_lineno, "Error: Attempt to Allocate the Same Memory Block with Freeing it First!" ); @@ -1036,7 +1177,7 @@ static void *mem_alloc_block( size_t size, const char *size_str ) /* Fill Memory Block with Magic Value or 0 */ fill_value = MAGIC_VALUE_USED; - if ( IS_CALLOC( size_str ) ) + if ( size_str[0] == 'c' ) { fill_value = 0x00000000; } @@ -1294,6 +1435,11 @@ void mem_free( const char *func_name, int func_lineno, void *ptr ) /* Check, if Out-Of-Bounds Access has been Detected */ ptr_record->OOB_Flag = mem_check_OOB( ptr_record ); +#ifdef MEM_COUNT_DETAILS + /* Export heap memory de-allocation record to the .csv file */ + fprintf( fid_csv_filename, "D,%d,%s,%d,%d\n", update_cnt, ptr_record->name, ptr_record->lineno, ptr_record->block_size ); +#endif + /* De-Allocate Memory Block */ tmp_ptr = (char *) ptr; tmp_ptr -= BLOCK_ROUNDING; @@ -1332,11 +1478,11 @@ void mem_free( const char *func_name, int func_lineno, void *ptr ) void update_mem( void ) { int i, j, flag_alloc = -1, i_record; - int32_t size_current_intra_frame_heap; + int size_current_intra_frame_heap; int *list_current_intra_frame_heap = NULL, n_items_current_intra_frame_heap; allocator_record *ptr_record; - /* process the heap allocation call tree */ + /* process the heap allocation call tree and prepare lists of intra-frame and inter-frame heap memory blocks for this frame */ n_items_current_intra_frame_heap = 0; size_current_intra_frame_heap = 0; for ( i = 0; i < heap_allocation_call_tree_size; i++ ) @@ -1364,7 +1510,7 @@ void update_mem( void ) memset( list_current_intra_frame_heap, -1, heap_allocation_call_tree_size * sizeof( int ) ); } - /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */ + /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */ if ( i_record == 0 ) { flag_alloc = 1; @@ -1384,23 +1530,7 @@ void update_mem( void ) list_current_intra_frame_heap[n_items_current_intra_frame_heap++] = i_record; size_current_intra_frame_heap += ptr_record->block_size; - /* check, if this is the new worst-case */ - if ( size_current_intra_frame_heap > size_wc_intra_frame_heap ) - { - if ( n_items_current_intra_frame_heap >= max_items_wc_intra_frame_heap ) - { - /* resize list, if needed */ - max_items_wc_intra_frame_heap = n_items_current_intra_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP; - list_wc_intra_frame_heap = realloc( list_wc_intra_frame_heap, max_items_wc_intra_frame_heap * sizeof( int ) ); - } - - /* save to wc list */ - memmove( list_wc_intra_frame_heap, list_current_intra_frame_heap, n_items_current_intra_frame_heap * sizeof( int ) ); - n_items_wc_intra_frame_heap = n_items_current_intra_frame_heap; - size_wc_intra_frame_heap = size_current_intra_frame_heap; - location_wc_intra_frame_heap = update_cnt; - ptr_record->wc_heap_size_intra_frame = ptr_record->block_size; - } + /* no need to re-size the list -> the initially allocated size should be large enough */ } else { @@ -1451,23 +1581,6 @@ void update_mem( void ) list_current_inter_frame_heap[n_items_current_inter_frame_heap++] = i_record; size_current_inter_frame_heap += ptr_record->block_size; - - /* check, if this is the new worst-case */ - if ( size_current_inter_frame_heap > size_wc_inter_frame_heap ) - { - if ( n_items_current_inter_frame_heap >= max_items_wc_inter_frame_heap ) - { - /* resize list, if needed */ - max_items_wc_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP; - list_wc_inter_frame_heap = realloc( list_wc_inter_frame_heap, max_items_wc_inter_frame_heap * sizeof( int ) ); - } - - memmove( list_wc_inter_frame_heap, list_current_inter_frame_heap, n_items_current_inter_frame_heap * sizeof( int ) ); - n_items_wc_inter_frame_heap = n_items_current_inter_frame_heap; - size_wc_inter_frame_heap = size_current_inter_frame_heap; - location_wc_inter_frame_heap = update_cnt; - ptr_record->wc_heap_size_inter_frame = ptr_record->block_size; - } } else { @@ -1490,9 +1603,60 @@ void update_mem( void ) } } + /* check, if this is the new worst-case for intra-frame heap memory */ + if ( size_current_intra_frame_heap > size_wc_intra_frame_heap ) + { + if ( n_items_current_intra_frame_heap >= max_items_wc_intra_frame_heap ) + { + /* resize the list, if needed */ + max_items_wc_intra_frame_heap = n_items_current_intra_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP; + list_wc_intra_frame_heap = realloc( list_wc_intra_frame_heap, max_items_wc_intra_frame_heap * sizeof( int ) ); + } + + /* copy current-frame list to worst-case list */ + memmove( list_wc_intra_frame_heap, list_current_intra_frame_heap, n_items_current_intra_frame_heap * sizeof( int ) ); + n_items_wc_intra_frame_heap = n_items_current_intra_frame_heap; + size_wc_intra_frame_heap = size_current_intra_frame_heap; + location_wc_intra_frame_heap = update_cnt; + + /* update the wc numbers in all individual records */ + for ( i = 0; i < n_items_wc_intra_frame_heap; i++ ) + { + i_record = list_wc_intra_frame_heap[i]; + ptr_record = &( allocation_list[i_record] ); + ptr_record->wc_heap_size_intra_frame = ptr_record->block_size; + } + } + + /* check, if this is the new worst-case for inter-frame heap memory */ + if ( size_current_inter_frame_heap > size_wc_inter_frame_heap ) + { + if ( n_items_current_inter_frame_heap >= max_items_wc_inter_frame_heap ) + { + /* resize list, if needed */ + max_items_wc_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP; + list_wc_inter_frame_heap = realloc( list_wc_inter_frame_heap, max_items_wc_inter_frame_heap * sizeof( int ) ); + } + + /* copy current-frame list to worst-case list */ + memmove( list_wc_inter_frame_heap, list_current_inter_frame_heap, n_items_current_inter_frame_heap * sizeof( int ) ); + n_items_wc_inter_frame_heap = n_items_current_inter_frame_heap; + size_wc_inter_frame_heap = size_current_inter_frame_heap; + location_wc_inter_frame_heap = update_cnt; + + /* update the wc numbers in all individual records */ + for ( i = 0; i < n_items_wc_inter_frame_heap; i++ ) + { + i_record = list_wc_inter_frame_heap[i]; + ptr_record = &( allocation_list[i_record] ); + ptr_record->wc_heap_size_inter_frame = ptr_record->block_size; + } + } + /* reset heap allocation call tree */ heap_allocation_call_tree_size = 0; + /* de-allocate list of intra-frame heap memory blocks in the current fraeme - it's needed only inside this function */ if ( list_current_intra_frame_heap ) { free( list_current_intra_frame_heap ); @@ -1607,7 +1771,7 @@ static void mem_count_summary( void ) if ( ptr_record->noccurances > 1 ) { - sprintf( size_str, "%dx%d %s", ptr_record->noccurances, (int) ( ( ptr_record->noccurances * ptr_record->wc_heap_size_intra_frame ) >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] ); + sprintf( size_str, "%dx%d %s", ptr_record->noccurances, (int) ( ptr_record->wc_heap_size_intra_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] ); } else { @@ -1636,7 +1800,7 @@ static void mem_count_summary( void ) continue; } ptr_record = &( allocation_list[index_record] ); - ptr_record->noccurances = 1; /* reset the counter because som blocks may be both, intra-frame and inter-frame */ + ptr_record->noccurances = 1; /* reset the counter as some blocks may have been both, intra-frame and inter-frame */ for ( j = i + 1; j < n_items_wc_inter_frame_heap; j++ ) { index = list_wc_inter_frame_heap[j]; @@ -1655,7 +1819,7 @@ static void mem_count_summary( void ) } /* Print Header */ - sprintf( buf, format_str, "Function Name", "Line", "Type", "Function Parameters", "Maximum Size", "Usage" ); + sprintf( buf, format_str, "Function Name", "Line", "Type", "Function Parameters", "Memory Size", "Usage" ); puts( buf ); length = strlen( buf ); sprintf( buf, "%0*d\n", (int) length - 1, 0 ); @@ -1690,11 +1854,11 @@ static void mem_count_summary( void ) sprintf( line_str, "%d", ptr_record->lineno ); /* prepare average usage & memory size strings */ - sprintf( usage_str, "%d%%", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 1 ) ) * 100.0f ) ); + sprintf( usage_str, "%d%%", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 0.1f ) ) * 100.0f + 0.5f ) ); if ( ptr_record->noccurances > 1 ) { - sprintf( size_str, "%dx%d %s", ptr_record->noccurances, (int) ( ( ptr_record->noccurances * ptr_record->wc_heap_size_inter_frame ) >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] ); + sprintf( size_str, "%dx%d %s", ptr_record->noccurances, (int) ( ptr_record->wc_heap_size_inter_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] ); } else { @@ -1712,45 +1876,6 @@ static void mem_count_summary( void ) return; } -/*-------------------------------------------------------------------* - * export_mem() - * - * Export detailed (per-item) information about heap memory usage to a .csv file - *--------------------------------------------------------------------*/ - -void export_mem( const char *csv_filename ) -{ - int i; - static FILE *fid = NULL; - allocator_record *record_ptr; - - if ( csv_filename == NULL || strcmp( csv_filename, "" ) == 0 ) - { - return; - } - - /* Check, if the .csv file has already been opened */ - if ( fid == NULL ) - { - fid = fopen( csv_filename, "wb" ); - - if ( fid == NULL ) - { - fprintf( stderr, "\nCannot open %s!\n\n", csv_filename ); - exit( -1 ); - } - } - - /* Export individual heap memory records to a .csv file */ - for ( i = 0; i < Num_Records; i++ ) - { - record_ptr = &( allocation_list[i] ); - fprintf( fid, "%s:%d,%d;", record_ptr->name, record_ptr->lineno, record_ptr->block_size ); - } - fprintf( fid, "\n" ); - - return; -} #endif /*-------------------------------------------------------------------* @@ -1773,7 +1898,16 @@ void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] ) for ( i = 0; i < nElem; i++ ) { - fprintf( stdout, "Program ROM size (%s): %d instruction words\n", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size ); + if ( Stat_Cnt_Size > 0 ) + { + /* words */ + fprintf( stdout, "Program ROM size (%s): %d words\n", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size ); + } + else + { + /* bytes (here, we assume that each instruction takes PROM_INST_SIZE bits of the PROM memory) */ + fprintf( stdout, "Program ROM size (%s): %d bytes\n", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size * ( PROM_INST_SIZE / 8 ) ); + } } for ( i = 0; i < nElem; i++ ) @@ -1864,9 +1998,15 @@ void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] ) if ( Stat_Cnt_Size > 0 ) { - fprintf( stdout, "\nNote: 1 word = %d bits\n", 8 << Stat_Cnt_Size ); - fprintf( stdout, "This is an optimistic estimate of memory consumption assuming that each variable type is stored with sizeof(type) bits\n" ); + /* words */ + fprintf( stdout, "\nNote: The Program ROM size is calculated under the assumption that 1 instruction word is stored with %d bits\n", 8 << Stat_Cnt_Size ); + } + else + { + /* bytes */ + fprintf( stdout, "\nNote: The Program ROM size is calculated under the assumption that 1 instruction word is stored with %d bits\n", PROM_INST_SIZE ); } + fprintf( stdout, "Note: The Data ROM size is calculated using the sizeof(type) built-in function\n" ); if ( n_items_wc_intra_frame_heap > 0 ) { @@ -1879,6 +2019,17 @@ void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] ) free( allocation_list ); } + /* De-allocate list of stack records */ + if ( stack_callers[0] != NULL ) + { + free( stack_callers[0] ); + } + + if ( stack_callers[1] != NULL ) + { + free( stack_callers[1] ); + } + /* De-allocate heap allocation call tree */ if ( heap_allocation_call_tree != NULL ) { @@ -1901,6 +2052,13 @@ void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] ) free( list_wc_inter_frame_heap ); } +#ifdef MEM_COUNT_DETAILS + if ( fid_csv_filename != NULL ) + { + fclose( fid_csv_filename ); + } +#endif + return; } @@ -1910,3 +2068,105 @@ void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] ) int cntr_push_pop = 0; /* global counter for checking balanced push_wmops()/pop_wmops() pairs when WMOPS is not activated */ #endif +#ifdef WMOPS +/* Global counter for the calculation of BASOP complexity */ +BASIC_OP *multiCounter = NULL; +int currCounter = 0; +int funcId_where_last_call_to_else_occurred; +long funcid_total_wmops_at_last_call_to_else; +int call_occurred = 1; + +BASIC_OP op_weight = { + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + 1, 1, 2, 2, 1, + 1, 1, 1, 3, 1, + + 1, 1, 1, 3, 1, + 4, 1, 18, 1, 1, + 2, 1, 2, 2, 1, + 1, 1, 1, 1, 1, + 3, 3, 3, 3, 1, + + 1, 1, 1, 1, 1, + 1, 1, 1, 2, + 1, 2, 2, 4, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 3, + 3, 3, 3, 3, 1, + 1, 1, 1, 1, 1, + 1, 1, 1, 4, 4, + 4, 8, 3, 4, 4, + + 5, 32, 3 +}; + +/* Set the counter group to use, default is zero */ +void Set_BASOP_WMOPS_counter( int counterId ) +{ + if ( ( counterId > num_wmops_records ) || ( counterId < 0 ) ) + { + currCounter = 0; + return; + } + currCounter = counterId; + call_occurred = 1; +} + +extern int32_t frame; + +long TotalWeightedOperation() +{ + int i; + unsigned int *ptr, *ptr2; + long tot; + + tot = 0; + ptr = (unsigned int *) &multiCounter[currCounter]; + ptr2 = (unsigned int *) &op_weight; + + for ( i = 0; i < ( int )( sizeof( multiCounter[currCounter] ) / sizeof( unsigned int ) ); i++ ) + { + tot += ( ( *ptr++ ) * ( *ptr2++ ) ); + } + + return ( tot ); +} + +long DeltaWeightedOperation( void ) +{ + long NewWOper, delta; + + NewWOper = TotalWeightedOperation(); + + delta = NewWOper - wmops[currCounter].LastWOper; + wmops[currCounter].LastWOper = NewWOper; + + return ( delta ); +} + +/* Resets the current BASOP WMOPS counter */ +void Reset_BASOP_WMOPS_counter( void ) +{ + int i; + long *ptr; + + /* clear the current BASOP operation counter before new frame begins */ + ptr = (long *) &multiCounter[currCounter]; + for ( i = 0; i < (int) ( sizeof( multiCounter[currCounter] ) / sizeof( long ) ); i++ ) + { + *ptr++ = 0; + } + + wmops[currCounter].LastWOper = 0; + + return; +} + +#endif + + + diff --git a/src/wmc_tool/test_data/ref/wmc_auto.h b/src/wmc_tool/test_data/ref/wmc_auto.h index 08597ad..3dae42b 100644 --- a/src/wmc_tool/test_data/ref/wmc_auto.h +++ b/src/wmc_tool/test_data/ref/wmc_auto.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -29,13 +29,12 @@ #pragma GCC system_header #endif -/* Real-time relationships */ -#define FRAMES_PER_SECOND 50.0 -#define MILLION_CYCLES 1e6 -#define WMOPS_BOOST_FAC ( 1.0f ) /* scaling factor for equalizing the difference between automatic and manual instrumentation */ -#define FAC ( FRAMES_PER_SECOND / MILLION_CYCLES * WMOPS_BOOST_FAC ) -#define NUM_INST 20 /* Total number of instruction types (in enum below) */ +#ifndef INT_MAX +#define INT_MAX 32767 +#endif +#define FRAMES_PER_SECOND 50.0 +#define PROM_INST_SIZE 32 /* number of bits of each program instruction when stored in the PROM memory (applied only when the user selects reporting in bytes) */ #ifdef WMOPS enum instructions @@ -59,7 +58,8 @@ enum instructions _TEST, _POWER, _LOG, - _MISC + _MISC, + NUM_INST }; #define _ADD_C 1 @@ -561,7 +561,6 @@ enum instructions extern double ops_cnt; extern double prom_cnt; extern double inst_cnt[NUM_INST]; -extern int ops_cnt_activ; void reset_wmops( void ); void push_wmops( const char *label ); @@ -614,14 +613,6 @@ extern int cntr_push_pop; #endif -/* mac & msu (Non Instrumented Versions) */ -#ifndef mac -#define mac( a, b, c ) ( ( a ) + ( b ) * ( c ) ) -#endif -#ifndef mac -#define msu( a, b, c ) ( ( a ) - ( b ) * ( c ) ) -#endif - #ifndef WMOPS /* DESACTIVATE the Counting Mechanism */ #define OP_COUNT_( op, n ) @@ -669,84 +660,99 @@ static int wmc_flag_ = 0; #endif /* Define all Macros without '{' & '}' (None of these should be called externally!) */ -#define ABS_( x ) OP_COUNT_( _ABS, ( x ) / WMOPS_BOOST_FAC ) -#define ADD_( x ) OP_COUNT_( _ADD, ( x ) / WMOPS_BOOST_FAC ) -#define MULT_( x ) OP_COUNT_( _MULT, ( x ) / WMOPS_BOOST_FAC ) -#define MAC_( x ) OP_COUNT_( _MAC, ( x ) / WMOPS_BOOST_FAC ) -#define MOVE_( x ) OP_COUNT_( _MOVE, ( x ) / WMOPS_BOOST_FAC ) -#define STORE_( x ) OP_COUNT_( _STORE, ( x ) / WMOPS_BOOST_FAC ) -#define LOGIC_( x ) OP_COUNT_( _LOGIC, ( x ) / WMOPS_BOOST_FAC ) -#define SHIFT_( x ) OP_COUNT_( _SHIFT, ( x ) / WMOPS_BOOST_FAC ) -#define BRANCH_( x ) OP_COUNT_( _BRANCH, ( x ) / WMOPS_BOOST_FAC ) -#define DIV_( x ) OP_COUNT_( _DIV, ( x ) / WMOPS_BOOST_FAC ) -#define SQRT_( x ) OP_COUNT_( _SQRT, ( x ) / WMOPS_BOOST_FAC ) -#define TRANS_( x ) OP_COUNT_( _TRANS, ( x ) / WMOPS_BOOST_FAC ) +#define ABS_( x ) OP_COUNT_( _ABS, ( x ) ) +#define ADD_( x ) OP_COUNT_( _ADD, ( x ) ) +#define MULT_( x ) OP_COUNT_( _MULT, ( x ) ) +#define MAC_( x ) OP_COUNT_( _MAC, ( x ) ) +#define MOVE_( x ) OP_COUNT_( _MOVE, ( x ) ) +#define STORE_( x ) OP_COUNT_( _STORE, ( x ) ) +#define LOGIC_( x ) OP_COUNT_( _LOGIC, ( x ) ) +#define SHIFT_( x ) OP_COUNT_( _SHIFT, ( x ) ) +#define BRANCH_( x ) OP_COUNT_( _BRANCH, ( x ) ) +#define DIV_( x ) OP_COUNT_( _DIV, ( x ) ) +#define SQRT_( x ) OP_COUNT_( _SQRT, ( x ) ) +#define TRANS_( x ) OP_COUNT_( _TRANS, ( x ) ) #define POWER_( x ) TRANS_( x ) #define LOG_( x ) TRANS_( x ) -#define LOOP_( x ) OP_COUNT_( _LOOP, ( x ) / WMOPS_BOOST_FAC ) -#define INDIRECT_( x ) OP_COUNT_( _INDIRECT, ( x ) / WMOPS_BOOST_FAC ) -#define PTR_INIT_( x ) OP_COUNT_( _PTR_INIT, ( x ) / WMOPS_BOOST_FAC ) -#define FUNC_( x ) ( OP_COUNT_( _MOVE, ( x ) / WMOPS_BOOST_FAC ), OP_COUNT_( _FUNC, 1 ) ) +#define LOOP_( x ) OP_COUNT_( _LOOP, ( x ) ) +#define INDIRECT_( x ) OP_COUNT_( _INDIRECT, ( x ) ) +#define PTR_INIT_( x ) OP_COUNT_( _PTR_INIT, ( x ) ) +#define FUNC_( x ) ( OP_COUNT_( _MOVE, ( x ) ), OP_COUNT_( _FUNC, 1 ) ) #define MISC_( x ) ABS_( x ) /* Math Operations */ -#define abs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), abs ) -#define fabs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), fabs ) -#define labs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), labs ) -#define floor_ OP_COUNT_WRAPPER1_( MISC_( 1 ), floor ) -#define sqrt_ OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrt ) -#define pow_ OP_COUNT_WRAPPER1_( POWER_( 1 ), pow ) -#define exp_ OP_COUNT_WRAPPER1_( POWER_( 1 ), exp ) -#define log_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log ) -#define log10_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log10 ) -#define cos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cos ) -#define sin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sin ) -#define tan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tan ) -#define acos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), acos ) -#define asin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), asin ) -#define atan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan ) -#define atan2_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan2 ) -#define cosh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cosh ) -#define sinh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinh ) -#define tanh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanh ) -#define fmod_ OP_COUNT_WRAPPER1_( DIV_( 1 ), fmod ) -/* these macros use any local macros already defined */ -/* min/max and their Variants */ -#define min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), min( ( a ), ( b ) ) ) -#define max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), max( ( a ), ( b ) ) ) -#define MIN_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MIN( ( a ), ( b ) ) ) -#define MAX_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MAX( ( a ), ( b ) ) ) -#define Min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Min( ( a ), ( b ) ) ) -#define Max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Max( ( a ), ( b ) ) ) -/* Square and its Variants */ -#define sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), sqr( ( x ) ) ) -#define Sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Sqr( ( x ) ) ) -#define SQR_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQR( ( x ) ) ) -#define square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), square( ( x ) ) ) -#define Square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Square( ( x ) ) ) -#define SQUARE_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQUARE( ( x ) ) ) -/* Sign and its Variants */ -#define sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), sign( ( x ) ) ) -#define Sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), Sign( ( x ) ) ) -#define SIGN_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), SIGN( ( x ) ) ) -/* Square Root and its Variants */ -#define sqrtf_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrtf( ( x ) ) ) -/* Invert Square Root and its Variants */ -#define inv_sqrt_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), inv_sqrt( ( x ) ) ) -/* Others */ +#define abs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), abs ) +#define fabs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), fabs ) +#define fabsf_ OP_COUNT_WRAPPER1_( ABS_( 1 ), fabsf ) +#define labs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), labs ) +#define floor_ OP_COUNT_WRAPPER1_( MISC_( 1 ), floor ) +#define floorf_ OP_COUNT_WRAPPER1_( MISC_( 1 ), floorf ) +#define sqrt_ OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrt ) +#define sqrtf_ OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrtf ) +#define pow_ OP_COUNT_WRAPPER1_( POWER_( 1 ), pow ) +#define powf_ OP_COUNT_WRAPPER1_( POWER_( 1 ), powf ) +#define exp_ OP_COUNT_WRAPPER1_( POWER_( 1 ), exp ) +#define expf_ OP_COUNT_WRAPPER1_( POWER_( 1 ), expf ) +#define log_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log ) +#define logf_ OP_COUNT_WRAPPER1_( LOG_( 1 ), logf ) +#define log10_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log10 ) +#define log10f_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log10f ) +#define cos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cos ) +#define cosf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cosf ) +#define sin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sin ) +#define sinf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinf ) +#define tan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tan ) +#define tanf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanf ) +#define acos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), acos ) +#define acosf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), acosf ) +#define asin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), asin ) +#define asinf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), asinf ) +#define atan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan ) +#define atanf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atanf ) +#define atan2_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan2 ) +#define atan2f_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan2f ) +#define cosh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cosh ) +#define coshf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), coshf ) +#define sinh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinh ) +#define sinhf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinhf ) +#define tanh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanh ) +#define tanhf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanhf ) +#define fmod_ OP_COUNT_WRAPPER1_( DIV_( 1 ), fmod ) +#define fmodf_ OP_COUNT_WRAPPER1_( DIV_( 1 ), fmodf ) +#define frexp_ OP_COUNT_WRAPPER1_( MISC_( 2 ), frexp ) +#define frexpf_ OP_COUNT_WRAPPER1_( MISC_( 2 ), frexpf ) + +/* the macros below are instrumented versions of user-defined macros that might be used in the source code +/* representing some well-known and recognized mathematical operations (that are not defined in math.h) */ +/* Note: the 'wmc_flag_=wmc_flag_' is used to avoid warning: left-hand operand of comma expression has no effect with gcc */ + +#define min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), min( ( a ), ( b ) ) ) +#define max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), max( ( a ), ( b ) ) ) +#define MIN_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MIN( ( a ), ( b ) ) ) +#define MAX_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MAX( ( a ), ( b ) ) ) +#define Min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Min( ( a ), ( b ) ) ) +#define Max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Max( ( a ), ( b ) ) ) +#define sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), sqr( ( x ) ) ) +#define Sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Sqr( ( x ) ) ) +#define SQR_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQR( ( x ) ) ) +#define square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), square( ( x ) ) ) +#define Square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Square( ( x ) ) ) +#define SQUARE_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQUARE( ( x ) ) ) +#define sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), sign( ( x ) ) ) +#define Sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), Sign( ( x ) ) ) +#define SIGN_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), SIGN( ( x ) ) ) +#define inv_sqrt_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), inv_sqrt( ( x ) ) ) +#define inv_sqrtf_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), inv_sqrtf( ( x ) ) ) #define log_base_2_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log_base_2( ( x ) ) ) +#define log2_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2( ( x ) ) ) +#define log2f_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2f( ( x ) ) ) #define log2_f_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2_f( ( x ) ) ) -/* The 'wmc_flag_=wmc_flag_' is Used to Avoid: "warning: left-hand operand of comma expression has no effect" - with Cygwin gcc Compiler */ -#define _round_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, _round( ( x ) ) ) -#define round_f_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, round_f( ( x ) ) ) -#define _squant_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, _squant( ( x ) ) ) -/* Set Min/Max */ +#define _round_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, _round( ( x ) ) ) +#define round_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, round( ( x ) ) ) +#define round_f_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, round_f( ( x ) ) ) +#define roundf_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, roundf( ( x ) ) ) #define set_min_( a, b ) OP_COUNT_WRAPPER3_( ( ADD_( 1 ), BRANCH_( 1 ), MOVE_( 1 ) ), set_min( ( a ), ( b ) ) ) #define set_max_( a, b ) OP_COUNT_WRAPPER3_( ( ADD_( 1 ), BRANCH_( 1 ), MOVE_( 1 ) ), set_max( ( a ), ( b ) ) ) -/* mac & msu (Instrumented Versions) */ -#define mac_( a, b, c ) OP_COUNT_WRAPPER1_( MAC_( 1 ), mac( a, b, c ) ) -#define msu_( a, b, c ) OP_COUNT_WRAPPER1_( MAC_( 1 ), msu( a, b, c ) ) /* Functions */ #define func_( name, x ) OP_COUNT_WRAPPER1_( FUNC_( x ), name ) @@ -980,7 +986,8 @@ typedef enum { USE_BYTES = 0, USE_16BITS = 1, - USE_32BITS = 2 + USE_32BITS = 2, + USE_64BITS = 3 } Counting_Size; #if ( defined( _WIN32 ) && ( _MSC_VER <= 1800 ) && ( _MSC_VER >= 1300 ) ) @@ -1007,15 +1014,12 @@ void mem_free( const char *func_name, int func_lineno, void *ptr ); void reset_mem( Counting_Size cnt_size ); void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] ); -#ifdef MEM_COUNT_DETAILS -void export_mem( const char *csv_filename ); -#endif int push_stack( const char *filename, const char *fctname ); int pop_stack( const char *filename, const char *fctname ); #ifdef WMOPS_DETAIL -#define STACK_DEPTH_FCT_CALL ( push_wmops( __FUNCTION__ ), push_stack( __FILE__, __FUNCTION__ ) ) /* add push_wmops() in all function calls */ +#define STACK_DEPTH_FCT_CALL ( push_wmops( __FUNCTION__ " [WMC_AUTO]" ), push_stack( __FILE__, __FUNCTION__ ) ) /* add push_wmops() in all function calls */ #define STACK_DEPTH_FCT_RETURN ( pop_wmops(), pop_stack( __FILE__, __FUNCTION__ ) ) /* add pop_wmops() in all function returns */ #else #define STACK_DEPTH_FCT_CALL push_stack( __FILE__, __FUNCTION__ ) @@ -1031,7 +1035,6 @@ void reset_stack( void ); #define free_( ptr ) free( ptr ) #define reset_mem( cnt_size ) #define print_mem( Const_Data_PROM_Table ) -#define export_mem( csv_filename ) #define push_stack( file, fct ) #define pop_stack( file, fct ) @@ -1040,5 +1043,406 @@ void reset_stack( void ); #endif + +/* Global counter variable for calculation of complexity weight */ +typedef struct +{ + unsigned int add; /* Complexity Weight of 1 */ + unsigned int sub; /* Complexity Weight of 1 */ + unsigned int abs_s; /* Complexity Weight of 1 */ + unsigned int shl; /* Complexity Weight of 1 */ + unsigned int shr; /* Complexity Weight of 1 */ + + unsigned int extract_h; /* Complexity Weight of 1 */ + unsigned int extract_l; /* Complexity Weight of 1 */ + unsigned int mult; /* Complexity Weight of 1 */ + unsigned int L_mult; /* Complexity Weight of 1 */ + unsigned int negate; /* Complexity Weight of 1 */ + + unsigned int round; /* Complexity Weight of 1 */ + unsigned int L_mac; /* Complexity Weight of 1 */ + unsigned int L_msu; /* Complexity Weight of 1 */ + unsigned int L_macNs; /* Complexity Weight of 1 */ + unsigned int L_msuNs; /* Complexity Weight of 1 */ + + unsigned int L_add; /* Complexity Weight of 1 */ + unsigned int L_sub; /* Complexity Weight of 1 */ + unsigned int L_add_c; /* Complexity Weight of 2 */ + unsigned int L_sub_c; /* Complexity Weight of 2 */ + unsigned int L_negate; /* Complexity Weight of 1 */ + + unsigned int L_shl; /* Complexity Weight of 1 */ + unsigned int L_shr; /* Complexity Weight of 1 */ + unsigned int mult_r; /* Complexity Weight of 1 */ + unsigned int shr_r; /* Complexity Weight of 3 */ + unsigned int mac_r; /* Complexity Weight of 1 */ + + unsigned int msu_r; /* Complexity Weight of 1 */ + unsigned int L_deposit_h; /* Complexity Weight of 1 */ + unsigned int L_deposit_l; /* Complexity Weight of 1 */ + unsigned int L_shr_r; /* Complexity Weight of 3 */ + unsigned int L_abs; /* Complexity Weight of 1 */ + + unsigned int L_sat; /* Complexity Weight of 4 */ + unsigned int norm_s; /* Complexity Weight of 1 */ + unsigned int div_s; /* Complexity Weight of 18 */ + unsigned int norm_l; /* Complexity Weight of 1 */ + unsigned int move16; /* Complexity Weight of 1 */ + + unsigned int move32; /* Complexity Weight of 2 */ + unsigned int Logic16; /* Complexity Weight of 1 */ + unsigned int Logic32; /* Complexity Weight of 2 */ + unsigned int Test; /* Complexity Weight of 2 */ + unsigned int s_max; /* Complexity Weight of 1 */ + + unsigned int s_min; /* Complexity Weight of 1 */ + unsigned int L_max; /* Complexity Weight of 1 */ + unsigned int L_min; /* Complexity Weight of 1 */ + unsigned int L40_max; /* Complexity Weight of 1 */ + unsigned int L40_min; /* Complexity Weight of 1 */ + + unsigned int shl_r; /* Complexity Weight of 3 */ + unsigned int L_shl_r; /* Complexity Weight of 3 */ + unsigned int L40_shr_r; /* Complexity Weight of 3 */ + unsigned int L40_shl_r; /* Complexity Weight of 3 */ + unsigned int norm_L40; /* Complexity Weight of 1 */ + + unsigned int L40_shl; /* Complexity Weight of 1 */ + unsigned int L40_shr; /* Complexity Weight of 1 */ + unsigned int L40_negate; /* Complexity Weight of 1 */ + unsigned int L40_add; /* Complexity Weight of 1 */ + unsigned int L40_sub; /* Complexity Weight of 1 */ + + unsigned int L40_abs; /* Complexity Weight of 1 */ + unsigned int L40_mult; /* Complexity Weight of 1 */ + unsigned int L40_mac; /* Complexity Weight of 1 */ + unsigned int mac_r40; /* Complexity Weight of 2 */ + + unsigned int L40_msu; /* Complexity Weight of 1 */ + unsigned int msu_r40; /* Complexity Weight of 2 */ + unsigned int Mpy_32_16_ss; /* Complexity Weight of 2 */ + unsigned int Mpy_32_32_ss; /* Complexity Weight of 4 */ + unsigned int L_mult0; /* Complexity Weight of 1 */ + + unsigned int L_mac0; /* Complexity Weight of 1 */ + unsigned int L_msu0; /* Complexity Weight of 1 */ + unsigned int lshl; /* Complexity Weight of 1 */ + unsigned int lshr; /* Complexity Weight of 1 */ + unsigned int L_lshl; /* Complexity Weight of 1 */ + + unsigned int L_lshr; /* Complexity Weight of 1 */ + unsigned int L40_lshl; /* Complexity Weight of 1 */ + unsigned int L40_lshr; /* Complexity Weight of 1 */ + unsigned int s_and; /* Complexity Weight of 1 */ + unsigned int s_or; /* Complexity Weight of 1 */ + + unsigned int s_xor; /* Complexity Weight of 1 */ + unsigned int L_and; /* Complexity Weight of 1 */ + unsigned int L_or; /* Complexity Weight of 1 */ + unsigned int L_xor; /* Complexity Weight of 1 */ + unsigned int rotl; /* Complexity Weight of 3 */ + + unsigned int rotr; /* Complexity Weight of 3 */ + unsigned int L_rotl; /* Complexity Weight of 3 */ + unsigned int L_rotr; /* Complexity Weight of 3 */ + unsigned int L40_set; /* Complexity Weight of 3 */ + unsigned int L40_deposit_h; /* Complexity Weight of 1 */ + + unsigned int L40_deposit_l; /* Complexity Weight of 1 */ + unsigned int L40_deposit32; /* Complexity Weight of 1 */ + unsigned int Extract40_H; /* Complexity Weight of 1 */ + unsigned int Extract40_L; /* Complexity Weight of 1 */ + unsigned int L_Extract40; /* Complexity Weight of 1 */ + + unsigned int L40_round; /* Complexity Weight of 1 */ + unsigned int L_saturate40; /* Complexity Weight of 1 */ + unsigned int round40; /* Complexity Weight of 1 */ + unsigned int If; /* Complexity Weight of 4 */ + unsigned int Goto; /* Complexity Weight of 4 */ + + unsigned int Break; /* Complexity Weight of 4 */ + unsigned int Switch; /* Complexity Weight of 8 */ + unsigned int For; /* Complexity Weight of 3 */ + unsigned int While; /* Complexity Weight of 4 */ + unsigned int Continue; /* Complexity Weight of 4 */ + + unsigned int L_mls; /* Complexity Weight of 6 */ + unsigned int div_l; /* Complexity Weight of 32 */ + unsigned int i_mult; /* Complexity Weight of 3 */ +} BASIC_OP; + +#ifdef WMOPS +extern BASIC_OP *multiCounter; +extern int currCounter; + +/* Technical note : + * The following 3 variables are only used for correct complexity + * evaluation of the following structure : + * IF{ + * ... + * } ELSE IF { + * ... + * } ELSE IF { + * ... + * } + * ... + * } ELSE { + * ... + * } + */ +extern int funcId_where_last_call_to_else_occurred; +extern long funcid_total_wmops_at_last_call_to_else; +extern int call_occurred; + +extern long TotalWeightedOperation( void ); +long DeltaWeightedOperation( void ); + +void Set_BASOP_WMOPS_counter( int counterId ); +void Reset_BASOP_WMOPS_counter( void ); + +#endif + +/***************************************************************************** + * + * Function Name : FOR + * + * Purpose : + * + * The macro FOR should be used instead of the 'for' C statement. + * The complexity is independent of the number of loop iterations that are + * performed. + * + * Complexity weight : 3 (regardless of number of iterations). + * + *****************************************************************************/ +#ifndef WMOPS +#define FOR( a) for( a) + +#else +#define FOR( a) if( incrFor(), 0); else for( a) + +static __inline void incrFor( void) { + multiCounter[currCounter].For++; +} +#endif + + +/***************************************************************************** + * + * Function Name : WHILE + * + * Purpose : + * + * The macro WHILE should be used instead of the 'while' C statement. + * The complexity is proportional to the number of loop iterations that + * are performed. + * + * Complexity weight : 4 x 'number of loop iterations'. + * + *****************************************************************************/ +#ifndef WMOPS +#define WHILE( a) while( a) + +#else +#define WHILE( a) while( incrWhile(), a) + +static __inline void incrWhile( void) { + multiCounter[currCounter].While++; +} +#endif + + +/***************************************************************************** + * + * Function Name : DO + * + * Purpose : + * + * The macro DO should be used instead of the 'do' C statement. + * + * Complexity weight : 0 (complexity counted by WHILE macro). + * + *****************************************************************************/ +#ifndef WMOPS +#define DO do + +#else +#define DO do + +#endif + + +/***************************************************************************** + * + * Function Name : IF + * + * Purpose : + * + * The macro IF should : + * + * - not be used when : + * - the 'if' structure does not have any 'else if' nor 'else' statement + * - and it conditions only one DSP basic operations. + * + * - be used instead of the 'if' C statement in every other case : + * - when there is an 'else' or 'else if' statement, + * - or when the 'if' conditions several DSP basic operations, + * - or when the 'if' conditions a function call. + * + * Complexity weight : 4 + * + *****************************************************************************/ +#ifndef WMOPS +#define IF( a) if( a) + +#else +#define IF( a) if( incrIf(), a) + +static __inline void incrIf( void) { + /* Technical note : + * If the "IF" operator comes just after an "ELSE", its counter + * must not be incremented. + */ + if ( ( currCounter != funcId_where_last_call_to_else_occurred ) || ( TotalWeightedOperation() != funcid_total_wmops_at_last_call_to_else ) || ( call_occurred == 1 ) ) + { + multiCounter[currCounter].If++; + } + + call_occurred = 0; + funcId_where_last_call_to_else_occurred = INT_MAX; +} +#endif + + +/***************************************************************************** + * + * Function Name : ELSE + * + * Purpose : + * + * The macro ELSE should be used instead of the 'else' C statement. + * + * Complexity weight : 4 + * + *****************************************************************************/ +#ifndef WMOPS +#define ELSE else + +#else +#define ELSE else if( incrElse(), 0) ; else + +static __inline void incrElse( void) { + multiCounter[currCounter].If++; + + /* We keep track of the funcId of the last function + * which used ELSE {...} structure. + */ + funcId_where_last_call_to_else_occurred = currCounter; + + /* We keep track of the number of WMOPS of this funcId + * when the ELSE macro was called. + */ + funcid_total_wmops_at_last_call_to_else = TotalWeightedOperation(); + + /* call_occurred is set to 0, in order to count the next IF (if necessary) + */ + call_occurred = 0; +} +#endif + + +/***************************************************************************** + * + * Function Name : SWITCH + * + * Purpose : + * + * The macro SWITCH should be used instead of the 'switch' C statement. + * + * Complexity weight : 8 + * + *****************************************************************************/ +#ifndef WMOPS +#define SWITCH( a) switch( a) + +#else +#define SWITCH( a) switch( incrSwitch(), a) + +static __inline void incrSwitch( void) { + multiCounter[currCounter].Switch++; +} +#endif + + +/***************************************************************************** + * + * Function Name : CONTINUE + * + * Purpose : + * + * The macro CONTINUE should be used instead of the 'continue' C statement. + * + * Complexity weight : 4 + * + *****************************************************************************/ +#ifndef WMOPS +#define CONTINUE continue + +#else +#define CONTINUE if( incrContinue(), 0); else continue + +static __inline void incrContinue( void) { + multiCounter[currCounter].Continue++; +} +#endif + + +/***************************************************************************** + * + * Function Name : BREAK + * + * Purpose : + * + * The macro BREAK should be used instead of the 'break' C statement. + * + * Complexity weight : 4 + * + *****************************************************************************/ +#ifndef WMOPS +#define BREAK break + +#else +#define BREAK if( incrBreak(), 0) break; else break + +static __inline void incrBreak( void) { + multiCounter[currCounter].Break++; +} +#endif + + +/***************************************************************************** + * + * Function Name : GOTO + * + * Purpose : + * + * The macro GOTO should be used instead of the 'goto' C statement. + * + * Complexity weight : 4 + * + *****************************************************************************/ +#ifndef WMOPS +#define GOTO goto + +#else +#define GOTO if( incrGoto(), 0); else goto + +static __inline void incrGoto( void) { + multiCounter[currCounter].Goto++; +} +#endif + #endif /* WMOPS_H */ + + diff --git a/src/wmc_tool/test_data/src/main1.c b/src/wmc_tool/test_data/src/main1.c index 726f24e..3bb8680 100644 --- a/src/wmc_tool/test_data/src/main1.c +++ b/src/wmc_tool/test_data/src/main1.c @@ -57,3 +57,5 @@ int main( #endif return 0; } + +#undef WMC_TOOL_SKIP \ No newline at end of file diff --git a/src/wmc_tool/test_data/src/test_basop.c b/src/wmc_tool/test_data/src/test_basop.c index 42cb03e..ffbebd8 100644 --- a/src/wmc_tool/test_data/src/test_basop.c +++ b/src/wmc_tool/test_data/src/test_basop.c @@ -53,3 +53,5 @@ void weight_coef_a( const Word16 *a, Word16 *b, const Word16 ght ) return; } + +#undef WMC_TOOL_SKIP diff --git a/src/wmc_tool/test_data/src/test_basop32.c b/src/wmc_tool/test_data/src/test_basop32.c index a0e328e..b72be9c 100644 --- a/src/wmc_tool/test_data/src/test_basop32.c +++ b/src/wmc_tool/test_data/src/test_basop32.c @@ -2427,5 +2427,6 @@ Word32 L_msu0 (Word32 L_var3, Word16 var1, Word16 var2) { return (L_var_out); } +#undef WMC_TOOL_SKIP /* end of file */ diff --git a/src/wmc_tool/text_utils.cpp b/src/wmc_tool/text_utils.cpp index f2738c6..076669d 100644 --- a/src/wmc_tool/text_utils.cpp +++ b/src/wmc_tool/text_utils.cpp @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -454,10 +454,11 @@ char *mempwordicmp( const char *mem, const char *words ) /*-------------------------------------------------------------------* * itos (Integer to String) *-------------------------------------------------------------------*/ -char *itos( char *str, int value, int digits ) +char *itos( char *str, int value ) { size_t i, n; char *str2; + int digits = 3; /* Convert Value to String */ sprintf(str, "%d", value); @@ -555,9 +556,18 @@ int Extract_Value_From_File( { if ((ptr = strstr(line, line_keyword)) != NULL) { - while (!isdigit(*ptr++)); + /* skip the keyword */ + ptr += strlen(line_keyword); + + /* search for space followed by a number */ + while (!(isspace(ptr[0]) && isdigit(ptr[1]))) + { + ptr++; + } + fclose(fp); - return strtol(--ptr, &ptr2, 10); + + return strtol(ptr, &ptr2, 10); } } diff --git a/src/wmc_tool/text_utils.h b/src/wmc_tool/text_utils.h index b15a1b6..bfd1c44 100644 --- a/src/wmc_tool/text_utils.h +++ b/src/wmc_tool/text_utils.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -109,7 +109,7 @@ char *memwordicmp( const char *mem, const char *words ); char *strwordistr( const char *mem, const char *words ); char *mempwordicmp( const char *mem, const char *words ); -char *itos( char *str, int value, int digits = 3 ); +char *itos( char *str, int value ); char *Fix_FileName( char *ptr ); diff --git a/src/wmc_tool/wmc_auto_c.txt b/src/wmc_tool/wmc_auto_c.txt index ec1726b..1b3b85e 100644 --- a/src/wmc_tool/wmc_auto_c.txt +++ b/src/wmc_tool/wmc_auto_c.txt @@ -1,1912 +1,2172 @@ -"/*\r\n" -" * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved.\r\n" -" *\r\n" -" * This software is protected by copyright law and by international treaties. The source code, and all of its derivations,\r\n" -" * is provided by VoiceAge Corporation under the \"ITU-T Software Tools' General Public License\". Please, read the license file\r\n" -" * or refer to ITU-T Recommendation G.191 on \"SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS\".\r\n" -" *\r\n" -" * Any use of this software is permitted provided that this notice is not removed and that neither the authors nor\r\n" -" * VoiceAge Corporation are deemed to have made any representations as to the suitability of this software\r\n" -" * for any purpose nor are held responsible for any defects of this software. THERE IS NO WARRANTY FOR THIS SOFTWARE.\r\n" -" *\r\n" -" * Authors: Guy Richard, Vladimir Malenovsky (Vladimir.Malenovsky@USherbrooke.ca)\r\n" -" */\r\n" -"\r\n" -"#include \r\n" -"#include \r\n" -"#include \r\n" -"#include \r\n" -"#include \r\n" -"\r\n" -"#ifndef _MSC_VER\r\n" -"#include \r\n" -"#include \r\n" -"#else\r\n" -"#include \r\n" -"#endif\r\n" -"\r\n" -"#include \"wmc_auto.h\"\r\n" -"\r\n" -"\r\n" -"#define WMC_TOOL_SKIP /* Skip the instrumentation of this file, if invoked by accident */\r\n" -"\r\n" -"#ifdef WMOPS\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * Complexity counting tool\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"#define MAX_RECORDS 1024\r\n" -"#define MAX_CHAR 64\r\n" -"#define MAX_STACK 64\r\n" -"#define DOUBLE_MAX 0x80000000\r\n" -"\r\n" -"struct wmops_record\r\n" -"{\r\n" -" char label[MAX_CHAR];\r\n" -" long call_number;\r\n" -" long update_cnt;\r\n" -" int call_tree[MAX_RECORDS];\r\n" -" double start_selfcnt;\r\n" -" double current_selfcnt;\r\n" -" double max_selfcnt;\r\n" -" double min_selfcnt;\r\n" -" double tot_selfcnt;\r\n" -" double start_cnt; /* The following take into account the decendants */\r\n" -" double current_cnt;\r\n" -" double max_cnt;\r\n" -" double min_cnt;\r\n" -" double tot_cnt;\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" int32_t current_call_number;\r\n" -" double wc_cnt;\r\n" -" double wc_selfcnt;\r\n" -" int32_t wc_call_number;\r\n" -"#endif\r\n" -"};\r\n" -"\r\n" -"double ops_cnt;\r\n" -"double prom_cnt;\r\n" -"double inst_cnt[NUM_INST];\r\n" -"\r\n" -"static struct wmops_record wmops[MAX_RECORDS];\r\n" -"static int stack[MAX_STACK];\r\n" -"static int sptr;\r\n" -"static int num_records;\r\n" -"static int current_record;\r\n" -"static long update_cnt;\r\n" -"static double start_cnt;\r\n" -"static double max_cnt;\r\n" -"static double min_cnt;\r\n" -"static double inst_cnt_wc[NUM_INST];\r\n" -"static long fnum_cnt_wc;\r\n" -"\r\n" -"static int *heap_allocation_call_tree = NULL, heap_allocation_call_tree_size = 0, heap_allocation_call_tree_max_size = 0;\r\n" -"\r\n" -"\r\n" -"void reset_wmops( void )\r\n" -"{\r\n" -" int i, j;\r\n" -"\r\n" -" for ( i = 0; i < MAX_RECORDS; i++ )\r\n" -" {\r\n" -" strcpy( &wmops[i].label[0], \"\\0\" );\r\n" -" wmops[i].call_number = 0;\r\n" -" wmops[i].update_cnt = 0;\r\n" -" for ( j = 0; j < MAX_RECORDS; j++ )\r\n" -" {\r\n" -" wmops[i].call_tree[j] = -1;\r\n" -" }\r\n" -" wmops[i].start_selfcnt = 0.0;\r\n" -" wmops[i].current_selfcnt = 0.0;\r\n" -" wmops[i].max_selfcnt = 0.0;\r\n" -" wmops[i].min_selfcnt = DOUBLE_MAX;\r\n" -" wmops[i].tot_selfcnt = 0.0;\r\n" -" wmops[i].start_cnt = 0.0;\r\n" -" wmops[i].current_cnt = 0.0;\r\n" -" wmops[i].max_cnt = 0.0;\r\n" -" wmops[i].min_cnt = DOUBLE_MAX;\r\n" -" wmops[i].tot_cnt = 0.0;\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" wmops[i].wc_cnt = 0.0;\r\n" -" wmops[i].wc_selfcnt = 0.0;\r\n" -" wmops[i].current_call_number = 0;\r\n" -"#endif\r\n" -" }\r\n" -"\r\n" -" for ( i = 0; i < MAX_STACK; i++ )\r\n" -" {\r\n" -" stack[i] = -1;\r\n" -" }\r\n" -" sptr = 0;\r\n" -" num_records = 0;\r\n" -" current_record = -1;\r\n" -" update_cnt = 0;\r\n" -"\r\n" -" max_cnt = 0.0;\r\n" -" min_cnt = DOUBLE_MAX;\r\n" -" start_cnt = 0.0;\r\n" -" ops_cnt = 0.0;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"void push_wmops( const char *label )\r\n" -"{\r\n" -" int new_flag;\r\n" -" int i, j;\r\n" -"\r\n" -" /* Check if new function record label */\r\n" -" new_flag = 1;\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" if ( strcmp( wmops[i].label, label ) == 0 )\r\n" -" {\r\n" -" new_flag = 0;\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Configure new record */\r\n" -" if ( new_flag )\r\n" -" {\r\n" -" if ( num_records >= MAX_RECORDS )\r\n" -" {\r\n" -" fprintf( stdout, \"push_wmops(): exceeded MAX_RECORDS count.\\n\\n\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -" strcpy( wmops[i].label, label );\r\n" -" num_records++;\r\n" -" }\r\n" -"\r\n" -" /* Push current context onto stack */\r\n" -" if ( current_record >= 0 )\r\n" -" {\r\n" -" if ( sptr >= MAX_STACK )\r\n" -" {\r\n" -" fprintf( stdout, \"\\r push_wmops(): stack exceeded, try inreasing MAX_STACK\\n\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -" stack[sptr++] = current_record;\r\n" -"\r\n" -" /* accumulate op counts */\r\n" -" wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt;\r\n" -"\r\n" -" /* update call tree */\r\n" -" for ( j = 0; j < MAX_RECORDS; j++ )\r\n" -" {\r\n" -" if ( wmops[i].call_tree[j] == current_record )\r\n" -" {\r\n" -" break;\r\n" -" }\r\n" -" else if ( wmops[i].call_tree[j] == -1 )\r\n" -" {\r\n" -" wmops[i].call_tree[j] = current_record;\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* init current record */\r\n" -" current_record = i;\r\n" -" wmops[current_record].start_selfcnt = ops_cnt;\r\n" -" wmops[current_record].start_cnt = ops_cnt;\r\n" -" wmops[current_record].call_number++;\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" wmops[current_record].current_call_number++;\r\n" -"#endif\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"void pop_wmops( void )\r\n" -"{\r\n" -"\r\n" -" /* Check for underflow */\r\n" -" if ( current_record < 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"\\r pop_wmops(): stack underflow, too many calls to pop_wmops()\\n\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* update count of current record */\r\n" -" wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt;\r\n" -" wmops[current_record].current_cnt += ops_cnt - wmops[current_record].start_cnt;\r\n" -"\r\n" -" /* Get back previous context from stack */\r\n" -" if ( sptr > 0 )\r\n" -" {\r\n" -" current_record = stack[--sptr];\r\n" -" wmops[current_record].start_selfcnt = ops_cnt;\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" current_record = -1;\r\n" -" }\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"void update_wmops( void )\r\n" -"{\r\n" -" int i;\r\n" -" double current_cnt;\r\n" -"#ifdef WMOPS_PER_FRAME\r\n" -" static FILE *fid = NULL;\r\n" -" const char filename[] = \"wmops_analysis\";\r\n" -" float tmpF;\r\n" -"#endif\r\n" -"\r\n" -" if ( sptr != 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"update_wmops(): Stack must be empty!\\n\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -"#ifdef WMOPS_PER_FRAME\r\n" -" /* Check, if the output file has already been opened */\r\n" -" if ( fid == NULL )\r\n" -" {\r\n" -" fid = fopen( filename, \"wb\" );\r\n" -"\r\n" -" if ( fid == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"\\nCannot open %s!\\n\\n\", filename );\r\n" -" exit( -1 );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Write current complexity to the external file */\r\n" -" tmpF = (float) ( FAC * wmops[0].current_cnt );\r\n" -" fwrite( &tmpF, sizeof( float ), 1, fid );\r\n" -"#endif\r\n" -"\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" if ( ops_cnt - start_cnt > max_cnt )\r\n" -" {\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" wmops[i].wc_cnt = wmops[i].current_cnt;\r\n" -" wmops[i].wc_selfcnt = wmops[i].current_selfcnt;\r\n" -" wmops[i].wc_call_number = wmops[i].current_call_number;\r\n" -" }\r\n" -" }\r\n" -"#endif\r\n" -"\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" wmops[i].tot_selfcnt += wmops[i].current_selfcnt;\r\n" -" wmops[i].tot_cnt += wmops[i].current_cnt;\r\n" -"\r\n" -" if ( wmops[i].current_selfcnt > 0 )\r\n" -" {\r\n" -" if ( wmops[i].current_selfcnt > wmops[i].max_selfcnt )\r\n" -" {\r\n" -" wmops[i].max_selfcnt = wmops[i].current_selfcnt;\r\n" -" }\r\n" -"\r\n" -" if ( wmops[i].current_selfcnt < wmops[i].min_selfcnt )\r\n" -" {\r\n" -" wmops[i].min_selfcnt = wmops[i].current_selfcnt;\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" wmops[i].current_selfcnt = 0;\r\n" -"\r\n" -" if ( wmops[i].current_cnt > 0 )\r\n" -" {\r\n" -" if ( wmops[i].current_cnt > wmops[i].max_cnt )\r\n" -" {\r\n" -" wmops[i].max_cnt = wmops[i].current_cnt;\r\n" -" }\r\n" -"\r\n" -" if ( wmops[i].current_cnt < wmops[i].min_cnt )\r\n" -" {\r\n" -" wmops[i].min_cnt = wmops[i].current_cnt;\r\n" -" }\r\n" -"\r\n" -" wmops[i].update_cnt++;\r\n" -" }\r\n" -"\r\n" -" wmops[i].current_cnt = 0;\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" wmops[i].current_call_number = 0;\r\n" -"#endif\r\n" -" }\r\n" -"\r\n" -" current_cnt = ops_cnt - start_cnt;\r\n" -" if ( current_cnt > max_cnt )\r\n" -" {\r\n" -" max_cnt = current_cnt;\r\n" -"\r\n" -" for ( i = 0; i < NUM_INST; i++ )\r\n" -" {\r\n" -" inst_cnt_wc[i] = inst_cnt[i];\r\n" -" }\r\n" -"\r\n" -" fnum_cnt_wc = update_cnt + 1;\r\n" -" }\r\n" -"\r\n" -" if ( current_cnt < min_cnt )\r\n" -" {\r\n" -" min_cnt = current_cnt;\r\n" -" }\r\n" -"\r\n" -" for ( i = 0; i < NUM_INST; i++ )\r\n" -" {\r\n" -" inst_cnt[i] = 0.0;\r\n" -" }\r\n" -"\r\n" -" start_cnt = ops_cnt;\r\n" -"\r\n" -" if ( heap_allocation_call_tree_size > 0 )\r\n" -" {\r\n" -" /* update intra-frame heap memory and inter-frame heap memory*/\r\n" -" update_mem();\r\n" -" }\r\n" -"\r\n" -" /* increment frame counter */\r\n" -" update_cnt++;\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"void print_wmops( void )\r\n" -"{\r\n" -" int i;\r\n" -"\r\n" -" char *sfmts = \"%20s %8s %8s %7s %7s\\n\";\r\n" -" char *dfmts = \"%20s %8.2f %8.3f %7.3f %7.3f\\n\";\r\n" -" char *sfmt = \"%20s %8s %8s %7s %7s %7s %7s %7s\\n\";\r\n" -" char *dfmt = \"%20s %8.2f %8.3f %7.3f %7.3f %7.3f %7.3f %7.3f\\n\";\r\n" -"\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" int j, label_len, max_label_len;\r\n" -" char *sfmtt = \"%20s %4s %15s\\n\";\r\n" -" char *dfmtt = \"%20s %4d \";\r\n" -"#endif\r\n" -"\r\n" -" fprintf( stdout, \"\\n\\n --- Complexity analysis [WMOPS] --- \\n\\n\" );\r\n" -"\r\n" -" fprintf( stdout, \"%54s %23s\\n\", \"|------ SELF ------|\", \"|--- CUMULATIVE ---|\" );\r\n" -" fprintf( stdout, sfmt, \" routine\", \" calls\", \" min \", \" max \", \" avg \", \" min \", \" max \", \" avg \" );\r\n" -" fprintf( stdout, sfmt, \"---------------\", \"------\", \"------\", \"------\", \"------\", \"------\", \"------\", \"------\" );\r\n" -"\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" fprintf( stdout, dfmt, wmops[i].label, update_cnt == 0 ? 0 : (float) wmops[i].call_number / update_cnt,\r\n" -" wmops[i].min_selfcnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_selfcnt,\r\n" -" FAC * wmops[i].max_selfcnt,\r\n" -" wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_selfcnt / wmops[i].update_cnt,\r\n" -" wmops[i].min_cnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_cnt,\r\n" -" FAC * wmops[i].max_cnt,\r\n" -" wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_cnt / wmops[i].update_cnt );\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, sfmts, \"---------------\", \"------\", \"------\", \"------\", \"------\" );\r\n" -" fprintf( stdout, dfmts, \"total\", (float) update_cnt, FAC * min_cnt, FAC * max_cnt, update_cnt == 0 ? 0 : FAC * ops_cnt / update_cnt );\r\n" -" fprintf( stdout, \"\\n\" );\r\n" -"\r\n" -"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n" -" /* calculate maximum label length for compact prinout */\r\n" -" max_label_len = 0;\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" label_len = strlen( wmops[i].label );\r\n" -" if ( label_len > max_label_len )\r\n" -" {\r\n" -" max_label_len = label_len;\r\n" -" }\r\n" -" }\r\n" -" max_label_len += 4;\r\n" -"\r\n" -" fprintf( stdout, \"\\nComplexity analysis for the worst-case frame %ld:\\n\", fnum_cnt_wc );\r\n" -" fprintf( stdout, \"%*s %8s %10s %12s\\n\", max_label_len, \" routine\", \" calls\", \" SELF\", \" CUMULATIVE\" );\r\n" -" fprintf( stdout, \"%*s %8s %10s %10s\\n\", max_label_len, \"---------------\", \"------\", \"------\", \"----------\" );\r\n" -"\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" fprintf( stdout, \"%*s %8d %10.3f %12.3f\\n\", max_label_len, wmops[i].label, wmops[i].wc_call_number, FAC * wmops[i].wc_selfcnt, FAC * wmops[i].wc_cnt );\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, \"\\nCall Tree:\\n\\n\" );\r\n" -" fprintf( stdout, sfmtt, \" function\", \"num\", \"called by: \" );\r\n" -" fprintf( stdout, sfmtt, \"---------------\", \"---\", \"--------------\" );\r\n" -"\r\n" -" for ( i = 0; i < num_records; i++ )\r\n" -" {\r\n" -" fprintf( stdout, dfmtt, wmops[i].label, i );\r\n" -" for ( j = 0; wmops[i].call_tree[j] != -1; j++ )\r\n" -" {\r\n" -" if ( j != 0 )\r\n" -" {\r\n" -" fprintf( stdout, \", \" );\r\n" -" }\r\n" -" fprintf( stdout, \"%d\", wmops[i].call_tree[j] );\r\n" -" }\r\n" -" fprintf( stdout, \"\\n\" );\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, sfmtt, \"---------------\", \"---\", \"--------------\" );\r\n" -" fprintf( stdout, \"\\n\\n\" );\r\n" -"\r\n" -" fprintf( stdout, \"\\nInstruction type analysis for the worst-case frame %ld:\\n\\n\", fnum_cnt_wc ); /* added -- JPA */\r\n" -" for ( i = 0; i < NUM_INST; i++ )\r\n" -" {\r\n" -" switch ( (enum instructions) i )\r\n" -" {\r\n" -" case _ADD:\r\n" -" fprintf( stdout, \"\\tAdds: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _ABS:\r\n" -" fprintf( stdout, \"\\tAbsolutes: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _MULT:\r\n" -" fprintf( stdout, \"\\tMultiplies: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _MAC:\r\n" -" fprintf( stdout, \"\\tMACs: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _MOVE:\r\n" -" fprintf( stdout, \"\\tMoves: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _STORE:\r\n" -" fprintf( stdout, \"\\tStores: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _LOGIC:\r\n" -" fprintf( stdout, \"\\tLogicals: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _SHIFT:\r\n" -" fprintf( stdout, \"\\tShifts: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _BRANCH:\r\n" -" fprintf( stdout, \"\\tBranches: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _DIV:\r\n" -" fprintf( stdout, \"\\tDivisions: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _SQRT:\r\n" -" fprintf( stdout, \"\\tSquare Root: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _TRANS:\r\n" -" fprintf( stdout, \"\\tTrans: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _FUNC:\r\n" -" fprintf( stdout, \"\\tFunc Call: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _LOOP:\r\n" -" fprintf( stdout, \"\\tLoop Init: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _INDIRECT:\r\n" -" fprintf( stdout, \"\\tIndirect Addr: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _PTR_INIT:\r\n" -" fprintf( stdout, \"\\tPointer Init: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _TEST:\r\n" -" fprintf( stdout, \"\\tExtra condit.: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _POWER:\r\n" -" fprintf( stdout, \"\\tExponential: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _LOG:\r\n" -" fprintf( stdout, \"\\tLogarithm: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" case _MISC:\r\n" -" fprintf( stdout, \"\\tAll other op.: %12.1f\\n\", inst_cnt_wc[i] );\r\n" -" break;\r\n" -" default:\r\n" -" fprintf( stdout, \"\\tERROR: Invalid instruction type: %d\\n\\n\", i );\r\n" -" }\r\n" -" }\r\n" -"#endif\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * Memory counting tool measuring RAM usage (stack and heap)\r\n" -" *\r\n" -" * Maximum RAM is measured by monitoring the total allocated memory (stack and heap) in each frame.\r\n" -" *\r\n" -" * Maximum stack is measured by monitoring the difference between the 'top' and 'bottom' of the stack. The 'bottom' of the stack is updated in each function\r\n" -" * with a macro 'func_start_' which is inserted automatically to all functions during the instrumentation process.\r\n" -" *\r\n" -" * Maximum heap is measured by summing the sizes of all memory blocks allocated by malloc() or calloc() and deallocated by free(). The maximum heap size is\r\n" -" * updated each time when the macros malloc_() or calloc_() is invoked. The macros 'malloc_ and calloc_' are inserted automatically during the instrumentation process.\r\n" -" * As part of heap measurements, intra-frame heap and inter-frame heap are measured separately. Intra-frame heap refers to heap memory which is allocated and deallocated\r\n" -" * within a single frame. Inter-frame heap, on the contrary, refers to heap memory which is reserved for more than one frame.\r\n" -" *\r\n" -" * In order to run the memory counting tool the function reset_mem(cnt_size) must be called at the beginning of the encoding/decoding process.\r\n" -" * The unit in which memory consumption is reported is set via the parameter 'cnt_size'. It can be set to 0 (bytes), 1 (32b words) or 2 (64b words).\r\n" -" * At the end of the encoding/decoding process, 'print_mem()' function may be called to print basic information about memory consumption. If the macro 'MEM_COUNT_DETAILS'\r\n" -" * is activated, detailed information is printed\r\n" -" *\r\n" -" * The macro 'WMOPS' needs to be activated to enable memory counting. To avoid the instrumentation of malloc()/calloc()/free() calls, use\r\n" -" * #define WMC_TOOL_SKIP ... #undef WMC_TOOL_SKIP macro pair around the malloc(), calloc() and free().\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"#define MAX_RECORDABLE_CALLS 100\r\n" -"#define MAX_FUNCTION_NAME_LENGTH 35 /* Maximum length that the function string will be truncated to */\r\n" -"#define MAX_PARAMS_LENGTH 50 /* Maximum length that the parameter string will be truncated to */\r\n" -"#define MAX_NUM_RECORDS 300 /* Initial maximum number of memory records -> mightb be increased during runtime, if needed */\r\n" -"#define MAX_NUM_RECORDS_REALLOC_STEP 50 /* When re-allocating the list of memory records, increase the number of records by this number */\r\n" -"\r\n" -"/* This is the value (in bytes) towards which the block size is rounded. For example, a block of 123 bytes, when using\r\n" -" a 32 bits system, will end up taking 124 bytes since the last unused byte cannot be used for another block. */\r\n" -"#ifdef MEM_ALIGN_64BITS\r\n" -"#define BLOCK_ROUNDING 8 /* Align on 64 Bits */\r\n" -"#else\r\n" -"#define BLOCK_ROUNDING 4 /* Align on 32 Bits */\r\n" -"#endif\r\n" -"\r\n" -"#define N_32BITS_BLOCKS ( BLOCK_ROUNDING / sizeof( int32_t ) )\r\n" -"\r\n" -"#define MAGIC_VALUE_OOB 0x12A534F0 /* Signature value which is inserted before and after each allocated memory block, used to detect out-of-bound access */\r\n" -"#define MAGIC_VALUE_USED ( ~MAGIC_VALUE_OOB ) /* Value used to pre-fill allocated memory blocks, used to calculate actual memory usage */\r\n" -"#define OOB_START 0x1 /* Flag indicating out-of-bounds access before memory block */\r\n" -"#define OOB_END 0x2 /* Flag indicating out-of-bounds access after memory block */\r\n" -"\r\n" -"#define ROUND_BLOCK_SIZE( n ) ( ( ( n ) + BLOCK_ROUNDING - 1 ) & ~( BLOCK_ROUNDING - 1 ) )\r\n" -"#define IS_CALLOC( str ) ( str[0] == 'c' )\r\n" -"\r\n" -"typedef struct\r\n" -"{\r\n" -" char function_name[MAX_FUNCTION_NAME_LENGTH + 1];\r\n" -" int16_t *stack_ptr;\r\n" -"} caller_info;\r\n" -"\r\n" -"caller_info stack_callers[2][MAX_RECORDABLE_CALLS];\r\n" -"\r\n" -"typedef struct\r\n" -"{\r\n" -" char name[MAX_FUNCTION_NAME_LENGTH + 1]; /* +1 for NUL */\r\n" -" char params[1 + MAX_PARAMS_LENGTH + 1]; /* +1 for 'm'/'c' alloc & +1 for NUL */\r\n" -" unsigned long hash;\r\n" -" int lineno;\r\n" -" void *block_ptr;\r\n" -" int block_size;\r\n" -" unsigned long total_block_size; /* Cumulative sum of the allocated size in the session */\r\n" -" unsigned long total_used_size; /* Cumulative sum of the used size in the session */\r\n" -" int wc_heap_size_intra_frame; /* Worst-Case Intra-Frame Heap Size */\r\n" -" int wc_heap_size_inter_frame; /* Worst-Case Inter-Frame Heap Size */\r\n" -" int frame_allocated; /* Frame number in which the Memory Block has been allocated (-1 if not allocated at the moment) */\r\n" -" int OOB_Flag;\r\n" -" int noccurances; /* Number of times that the memory block has been allocated in a frame */\r\n" -"} allocator_record;\r\n" -"\r\n" -"allocator_record *allocation_list = NULL;\r\n" -"\r\n" -"static int16_t *ptr_base_stack = 0; /* Pointer to the bottom of stack (base pointer). Stack grows up. */\r\n" -"static int16_t *ptr_current_stack = 0; /* Pointer to the current stack pointer */\r\n" -"static int16_t *ptr_max_stack = 0; /* Pointer to the maximum stack pointer (the farest point from the bottom of stack) */\r\n" -"static int32_t wc_stack_frame = 0; /* Frame corresponding to the worst-case stack usage */\r\n" -"static int32_t wc_ram_size, wc_ram_frame;\r\n" -"static int32_t current_heap_size;\r\n" -"static int current_calls = 0;\r\n" -"static char location_max_stack[256] = \"undefined\";\r\n" -"static int Num_Records, Max_Num_Records;\r\n" -"static size_t Stat_Cnt_Size = USE_BYTES;\r\n" -"static const char *Count_Unit[] = { \"bytes\", \"words\", \"words\" };\r\n" -"\r\n" -"static int *list_wc_intra_frame_heap, n_items_wc_intra_frame_heap, max_items_wc_intra_frame_heap, size_wc_intra_frame_heap, location_wc_intra_frame_heap;\r\n" -"static int *list_current_inter_frame_heap, n_items_current_inter_frame_heap, max_items_current_inter_frame_heap, size_current_inter_frame_heap;\r\n" -"static int *list_wc_inter_frame_heap, n_items_wc_inter_frame_heap, max_items_wc_inter_frame_heap, size_wc_inter_frame_heap, location_wc_inter_frame_heap;\r\n" -"\r\n" -"/* Local Functions */\r\n" -"static unsigned long malloc_hash( const char *func_name, int func_lineno, char *size_str );\r\n" -"allocator_record *get_mem_record( unsigned long *hash, const char *func_name, int func_lineno, char *size_str, int *index_record );\r\n" -"static void *mem_alloc_block( size_t size, const char *size_str );\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * reset_mem()\r\n" -" *\r\n" -" * Initialize/reset memory counting tool (stack and heap)\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void reset_mem( Counting_Size cnt_size )\r\n" -"{\r\n" -" int16_t something;\r\n" -" size_t tmp_size;\r\n" -"\r\n" -" /* initialize stack pointers */\r\n" -" ptr_base_stack = &something;\r\n" -" ptr_max_stack = ptr_base_stack;\r\n" -" ptr_current_stack = ptr_base_stack;\r\n" -"\r\n" -" Stat_Cnt_Size = cnt_size;\r\n" -"\r\n" -" /* Check, if sizeof(int32_t) is 4 bytes */\r\n" -" tmp_size = sizeof( int32_t );\r\n" -" if ( tmp_size != 4 )\r\n" -" {\r\n" -" fprintf( stderr, \"Error: Expecting 'int32_t' to be a 32 Bits Integer!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* create allocation list for malloc() memory blocks */\r\n" -" if ( allocation_list == NULL )\r\n" -" {\r\n" -" allocation_list = malloc( MAX_NUM_RECORDS * sizeof( allocator_record ) );\r\n" -" }\r\n" -"\r\n" -" if ( allocation_list == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"Error: Unable to Create List of Memory Blocks!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" Num_Records = 0;\r\n" -" Max_Num_Records = MAX_NUM_RECORDS;\r\n" -"\r\n" -" wc_ram_size = 0;\r\n" -" wc_ram_frame = -1;\r\n" -" current_heap_size = 0;\r\n" -"\r\n" -" /* heap allocation tree */\r\n" -" heap_allocation_call_tree_max_size = MAX_NUM_RECORDS;\r\n" -" if ( heap_allocation_call_tree == NULL )\r\n" -" {\r\n" -" heap_allocation_call_tree = (int *) malloc( heap_allocation_call_tree_max_size * sizeof( int ) );\r\n" -" memset( heap_allocation_call_tree, -1, heap_allocation_call_tree_max_size * sizeof( int ) );\r\n" -" }\r\n" -" heap_allocation_call_tree_size = 0;\r\n" -"\r\n" -" /* wc intra-frame heap */\r\n" -" max_items_wc_intra_frame_heap = MAX_NUM_RECORDS;\r\n" -" if ( list_wc_intra_frame_heap == NULL )\r\n" -" {\r\n" -" list_wc_intra_frame_heap = (int *) malloc( max_items_wc_intra_frame_heap * sizeof( int ) );\r\n" -" memset( list_wc_intra_frame_heap, -1, max_items_wc_intra_frame_heap * sizeof( int ) );\r\n" -" }\r\n" -" n_items_wc_intra_frame_heap = 0;\r\n" -" size_wc_intra_frame_heap = 0;\r\n" -" location_wc_intra_frame_heap = -1;\r\n" -"\r\n" -" /* current inter-frame heap */\r\n" -" max_items_current_inter_frame_heap = MAX_NUM_RECORDS;\r\n" -" if ( list_current_inter_frame_heap == NULL )\r\n" -" {\r\n" -" list_current_inter_frame_heap = (int *) malloc( max_items_current_inter_frame_heap * sizeof( int ) );\r\n" -" memset( list_current_inter_frame_heap, -1, max_items_current_inter_frame_heap * sizeof( int ) );\r\n" -" }\r\n" -" n_items_current_inter_frame_heap = 0;\r\n" -" size_current_inter_frame_heap = 0;\r\n" -"\r\n" -" /* wc inter-frame heap */\r\n" -" max_items_wc_inter_frame_heap = MAX_NUM_RECORDS;\r\n" -" if ( list_wc_inter_frame_heap == NULL )\r\n" -" {\r\n" -" list_wc_inter_frame_heap = (int *) malloc( max_items_wc_inter_frame_heap * sizeof( int ) );\r\n" -" memset( list_wc_inter_frame_heap, -1, max_items_wc_inter_frame_heap * sizeof( int ) );\r\n" -" }\r\n" -" n_items_wc_inter_frame_heap = 0;\r\n" -" size_wc_inter_frame_heap = 0;\r\n" -" location_wc_inter_frame_heap = -1;\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * reset_stack()\r\n" -" *\r\n" -" * Reset stack pointer\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void reset_stack( void )\r\n" -"{\r\n" -" int16_t something;\r\n" -"\r\n" -" /* initialize/reset stack pointers */\r\n" -" ptr_base_stack = &something;\r\n" -" ptr_max_stack = ptr_base_stack;\r\n" -" ptr_current_stack = ptr_base_stack;\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * push_stack()\r\n" -" *\r\n" -" * Check the current stack pointer and update the maximum stack pointer, if new maximum found.\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"int push_stack( const char *filename, const char *fctname )\r\n" -"{\r\n" -" int16_t something;\r\n" -" int32_t current_stack_size;\r\n" -"\r\n" -" ptr_current_stack = &something;\r\n" -"\r\n" -" (void) *filename; /* to avoid compilation warning */\r\n" -"\r\n" -" /* Is there room to save the caller's information? */\r\n" -" if ( current_calls >= MAX_RECORDABLE_CALLS )\r\n" -" { /* No */\r\n" -" fprintf( stderr, \"No more room to store call stack info. Please increase MAX_RECORDABLE_CALLS\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* Valid Function Name? */\r\n" -" if ( fctname[0] == 0 )\r\n" -" { /* No */\r\n" -" fprintf( stderr, \"Invalid function name for call stack info.\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* Save the Name of the Calling Function in the Table */\r\n" -" strncpy( stack_callers[0][current_calls].function_name, fctname, MAX_FUNCTION_NAME_LENGTH );\r\n" -" stack_callers[0][current_calls].function_name[MAX_FUNCTION_NAME_LENGTH] = 0; /* Nul Terminate */\r\n" -"\r\n" -" /* Save the Stack Pointer */\r\n" -" stack_callers[0][current_calls].stack_ptr = ptr_current_stack;\r\n" -"\r\n" -" /* Increase Stack Calling Tree Level */\r\n" -" current_calls++;\r\n" -"\r\n" -" /* Is this the First Time or the Worst Case? */\r\n" -" if ( ptr_current_stack < ptr_max_stack || ptr_max_stack == NULL )\r\n" -" { /* Yes */\r\n" -" /* Save Info about it */\r\n" -" ptr_max_stack = ptr_current_stack;\r\n" -"\r\n" -" wc_stack_frame = update_cnt; /* current frame number is stored in the variable update_cnt and updated in the function update_wmops() */\r\n" -" strncpy( location_max_stack, fctname, sizeof( location_max_stack ) - 1 );\r\n" -" location_max_stack[sizeof( location_max_stack ) - 1] = '\\0';\r\n" -"\r\n" -" /* Save Call Tree */\r\n" -" memmove( stack_callers[1], stack_callers[0], sizeof( caller_info ) * current_calls );\r\n" -"\r\n" -" /* Terminate the List (Unless Full) */\r\n" -" if ( current_calls < MAX_RECORDABLE_CALLS )\r\n" -" {\r\n" -" stack_callers[1][current_calls].function_name[0] = 0;\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Check, if This is the New Worst-Case RAM (stack + heap) */\r\n" -" current_stack_size = (int32_t) ( ( ( ptr_base_stack - ptr_current_stack ) * sizeof( int16_t ) ) );\r\n" -"\r\n" -" if ( current_stack_size < 0 )\r\n" -" {\r\n" -" /* prevent negative stack size */\r\n" -" current_stack_size = 0;\r\n" -" }\r\n" -"\r\n" -" if ( current_stack_size + current_heap_size > wc_ram_size )\r\n" -" {\r\n" -" wc_ram_size = current_stack_size + current_heap_size;\r\n" -" wc_ram_frame = update_cnt;\r\n" -" }\r\n" -"\r\n" -" return 0 /* for Now */;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * pop_stack()\r\n" -" *\r\n" -" * Remove stack caller entry from the list\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"int pop_stack( const char *filename, const char *fctname )\r\n" -"{\r\n" -" caller_info *caller_info_ptr;\r\n" -"\r\n" -" (void) *filename; /* to avoid compilation warning */\r\n" -"\r\n" -" /* Decrease Stack Calling */\r\n" -" current_calls--;\r\n" -"\r\n" -" /* Get Pointer to Caller Information */\r\n" -" caller_info_ptr = &stack_callers[0][current_calls];\r\n" -"\r\n" -" /* Check, if Names Match */\r\n" -" if ( strncmp( caller_info_ptr->function_name, fctname, MAX_FUNCTION_NAME_LENGTH ) != 0 )\r\n" -" {\r\n" -" fprintf( stderr, \"Invalid usage of pop_stack()\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* Erase Entry */\r\n" -" caller_info_ptr->function_name[0] = 0;\r\n" -"\r\n" -" /* Retrieve previous stack pointer */\r\n" -" if ( current_calls == 0 )\r\n" -" {\r\n" -" ptr_current_stack = ptr_base_stack;\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" ptr_current_stack = stack_callers[0][current_calls - 1].stack_ptr;\r\n" -" }\r\n" -"\r\n" -" return 0 /* for Now */;\r\n" -"}\r\n" -"\r\n" -"#ifdef MEM_COUNT_DETAILS\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * print_stack_call_tree()\r\n" -" *\r\n" -" * Print detailed information about worst-case stack usage\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static void print_stack_call_tree( void )\r\n" -"{\r\n" -" caller_info *caller_info_ptr;\r\n" -" int call_level;\r\n" -" char fctname[MAX_FUNCTION_NAME_LENGTH + 1];\r\n" -"\r\n" -" fprintf( stdout, \"\\nList of functions when maximum stack size is reached:\\n\\n\" );\r\n" -"\r\n" -" caller_info_ptr = &stack_callers[1][0];\r\n" -" for ( call_level = 0; call_level < MAX_RECORDABLE_CALLS; call_level++ )\r\n" -" {\r\n" -" /* Done? */\r\n" -" if ( caller_info_ptr->function_name[0] == 0 )\r\n" -" {\r\n" -" break;\r\n" -" }\r\n" -"\r\n" -" /* Print Name */\r\n" -" strncpy( fctname, caller_info_ptr->function_name, MAX_FUNCTION_NAME_LENGTH );\r\n" -" strcat( fctname, \"()\" );\r\n" -" fprintf( stdout, \"%-42s\", fctname );\r\n" -"\r\n" -" /* Print Stack Usage (Based on Difference) */\r\n" -" if ( call_level != 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"%lu %s\\n\", ( ( ( caller_info_ptr - 1 )->stack_ptr - caller_info_ptr->stack_ptr ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" fprintf( stdout, \"%lu %s\\n\", ( ( ptr_base_stack - caller_info_ptr->stack_ptr ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -"\r\n" -" /* Advance */\r\n" -" caller_info_ptr++;\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, \"\\n\" );\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"#endif\r\n" -"\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * mem_alloc()\r\n" -" *\r\n" -" * Creates new record, stores auxiliary information about which function allocated the memory, line number, parameters, etc.\r\n" -" * Finally, it allocates physical memory using malloc()\r\n" -" * The function also updates worst-case heap size and worst-case RAM size\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void *mem_alloc(\r\n" -" const char *func_name,\r\n" -" int func_lineno,\r\n" -" size_t size,\r\n" -" char *size_str /* the first char indicates m-alloc or c-alloc */ )\r\n" -"{\r\n" -" int index_record;\r\n" -" int32_t current_stack_size;\r\n" -" unsigned long hash;\r\n" -" allocator_record *ptr_record;\r\n" -"\r\n" -" if ( size == 0 )\r\n" -" {\r\n" -" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Size of Zero not Supported\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* Search for an existing record (that has been de-allocated before) */\r\n" -" index_record = 0;\r\n" -" while ( ( ptr_record = get_mem_record( &hash, func_name, func_lineno, size_str, &index_record ) ) != NULL )\r\n" -" {\r\n" -" if ( ptr_record->frame_allocated == -1 )\r\n" -" {\r\n" -" break;\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" index_record++;\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Create new record */\r\n" -" if ( ptr_record == NULL )\r\n" -" {\r\n" -" if ( Num_Records >= Max_Num_Records )\r\n" -" {\r\n" -" /* There is no room for a new record -> reallocate memory */\r\n" -" Max_Num_Records += MAX_NUM_RECORDS_REALLOC_STEP;\r\n" -" allocation_list = realloc( allocation_list, Max_Num_Records * sizeof( allocator_record ) );\r\n" -" }\r\n" -"\r\n" -" ptr_record = &( allocation_list[Num_Records] );\r\n" -"\r\n" -" /* Initialize new record */\r\n" -" ptr_record->hash = hash;\r\n" -" ptr_record->noccurances = 0;\r\n" -" ptr_record->total_block_size = 0;\r\n" -" ptr_record->total_used_size = 0;\r\n" -" ptr_record->frame_allocated = -1;\r\n" -" ptr_record->OOB_Flag = 0;\r\n" -" ptr_record->wc_heap_size_intra_frame = -1;\r\n" -" ptr_record->wc_heap_size_inter_frame = -1;\r\n" -"\r\n" -" index_record = Num_Records;\r\n" -" Num_Records++;\r\n" -" }\r\n" -"\r\n" -" /* Allocate memory block for the new record, add signature before the beginning and after the memory block and fill it with magic value */\r\n" -" ptr_record->block_ptr = mem_alloc_block( size, size_str );\r\n" -"\r\n" -" if ( ptr_record->block_ptr == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Error: Cannot Allocate Memory!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* Save all auxiliary information about the memory block */\r\n" -" strncpy( ptr_record->name, func_name, MAX_FUNCTION_NAME_LENGTH );\r\n" -" ptr_record->name[MAX_FUNCTION_NAME_LENGTH] = '\\0';\r\n" -" strncpy( ptr_record->params, size_str, MAX_PARAMS_LENGTH ); /* Note: The size string starts with either 'm' or 'c' to indicate 'm'alloc or 'c'alloc */\r\n" -" ptr_record->params[MAX_PARAMS_LENGTH] = '\\0';\r\n" -" ptr_record->lineno = func_lineno;\r\n" -" ptr_record->block_size = size;\r\n" -" ptr_record->total_block_size += size;\r\n" -"\r\n" -" if ( ptr_record->frame_allocated != -1 )\r\n" -" {\r\n" -" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Error: Attempt to Allocate the Same Memory Block with Freeing it First!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" ptr_record->frame_allocated = update_cnt; /* Store the current frame number -> later it will be used to determine the total duration */\r\n" -"\r\n" -" /* Update Heap Size in the current frame */\r\n" -" current_heap_size += ptr_record->block_size;\r\n" -"\r\n" -" /* Check, if this is the new Worst-Case RAM (stack + heap) */\r\n" -" current_stack_size = (int32_t) ( ( ( ptr_base_stack - ptr_current_stack ) * sizeof( int16_t ) ) );\r\n" -" if ( current_stack_size + current_heap_size > wc_ram_size )\r\n" -" {\r\n" -" wc_ram_size = current_stack_size + current_heap_size;\r\n" -" wc_ram_frame = update_cnt;\r\n" -" }\r\n" -"\r\n" -" /* Add new entry to the heap allocation call tree */\r\n" -" if ( heap_allocation_call_tree == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"Error: Heap allocation call tree not created!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* check, if the maximum size of the call tree has been reached -> resize if so */\r\n" -" if ( heap_allocation_call_tree_size >= heap_allocation_call_tree_max_size )\r\n" -" {\r\n" -" heap_allocation_call_tree_max_size += MAX_NUM_RECORDS_REALLOC_STEP;\r\n" -" heap_allocation_call_tree = (int *) realloc( heap_allocation_call_tree, heap_allocation_call_tree_max_size * sizeof( int ) );\r\n" -" }\r\n" -"\r\n" -" /* push new entry (positive number means push op, neagtive number means pop op; zero index must be converted to 0.01 :-) */\r\n" -" heap_allocation_call_tree[heap_allocation_call_tree_size++] = index_record;\r\n" -"\r\n" -" return ptr_record->block_ptr;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * mem_alloc_block()\r\n" -" *\r\n" -" * Physical allocation of memory using malloc(). Appends 'signature' before and after the block,\r\n" -" * pre-fills memory block with magic value\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static void *mem_alloc_block( size_t size, const char *size_str )\r\n" -"{\r\n" -" size_t rounded_size;\r\n" -" void *block_ptr;\r\n" -" char *tmp_ptr;\r\n" -" size_t n, f;\r\n" -" int32_t fill_value;\r\n" -" int32_t *ptr32;\r\n" -" int32_t mask, temp;\r\n" -"\r\n" -" /* Round Up Block Size */\r\n" -" rounded_size = ROUND_BLOCK_SIZE( size );\r\n" -"\r\n" -" /* Allocate memory using the standard malloc() by adding room for Signature Values */\r\n" -" block_ptr = malloc( rounded_size + BLOCK_ROUNDING * 2 );\r\n" -"\r\n" -" if ( block_ptr == NULL )\r\n" -" {\r\n" -" return NULL;\r\n" -" }\r\n" -"\r\n" -" /* Add Signature Before the Start of the Block */\r\n" -" ptr32 = (int32_t *) block_ptr;\r\n" -" n = N_32BITS_BLOCKS;\r\n" -" do\r\n" -" {\r\n" -" *ptr32++ = MAGIC_VALUE_OOB;\r\n" -" } while ( --n );\r\n" -"\r\n" -" /* Fill Memory Block with Magic Value or 0 */\r\n" -" fill_value = MAGIC_VALUE_USED;\r\n" -" if ( IS_CALLOC( size_str ) )\r\n" -" {\r\n" -" fill_value = 0x00000000;\r\n" -" }\r\n" -" n = size / sizeof( int32_t );\r\n" -" while ( n-- )\r\n" -" {\r\n" -" *ptr32++ = fill_value;\r\n" -" }\r\n" -"\r\n" -" /* Fill the Reminder of the Memory Block - After Rounding */\r\n" -" n = rounded_size - size;\r\n" -" f = n % sizeof( int32_t );\r\n" -" if ( f != 0 )\r\n" -" {\r\n" -" /* when filling with '0' need to adapt the magic value */\r\n" -" /* shift by [1->24, 2->16, 3->8] */\r\n" -" mask = 0xFFFFFFFF << ( ( sizeof( int32_t ) - f ) * 8 ); /* (1) */\r\n" -" temp = MAGIC_VALUE_OOB & mask;\r\n" -" if ( fill_value != 0x0 )\r\n" -" { /* for malloc merge fill value */\r\n" -" temp += ( ~mask ) & MAGIC_VALUE_USED;\r\n" -" } /* for calloc the code in (1) above already introduces zeros */\r\n" -" *ptr32++ = temp;\r\n" -" }\r\n" -" n /= sizeof( int32_t );\r\n" -" n += N_32BITS_BLOCKS;\r\n" -"\r\n" -" /* Add Signature After the End of Block */\r\n" -" do\r\n" -" {\r\n" -" *ptr32++ = MAGIC_VALUE_OOB;\r\n" -" } while ( --n );\r\n" -"\r\n" -" /* Adjust the Memory Block Pointer (Magic Value Before and After the Memory Block Requested) */\r\n" -" tmp_ptr = (char *) block_ptr;\r\n" -" tmp_ptr += BLOCK_ROUNDING;\r\n" -" block_ptr = (void *) tmp_ptr;\r\n" -"\r\n" -" return block_ptr;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * mem_set_usage()\r\n" -" *\r\n" -" * Calculates actual usage of memory block by checking the magic value that was used to pre-fill\r\n" -" * each memory block during its allocation\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static int mem_set_usage( allocator_record *record_ptr )\r\n" -"{\r\n" -" int total_bytes_used;\r\n" -"\r\n" -" size_t n;\r\n" -" int32_t *ptr32;\r\n" -" char *ptr8;\r\n" -" size_t total_bytes;\r\n" -" int32_t fill_value;\r\n" -"\r\n" -" fill_value = MAGIC_VALUE_USED;\r\n" -" if ( ( record_ptr->params[0] ) == 'c' )\r\n" -" {\r\n" -" fill_value = 0x00000000;\r\n" -" }\r\n" -"\r\n" -" total_bytes = record_ptr->block_size;\r\n" -"\r\n" -" /* Check 4 bytes at a time */\r\n" -" ptr32 = (int32_t *) record_ptr->block_ptr;\r\n" -" total_bytes_used = 0;\r\n" -" for ( n = total_bytes / sizeof( int32_t ); n > 0; n-- )\r\n" -" {\r\n" -" if ( *ptr32++ != fill_value )\r\n" -" {\r\n" -" total_bytes_used += sizeof( int32_t );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Check remaining bytes (If Applicable) 1 byte at a time */\r\n" -" ptr8 = (char *) ptr32;\r\n" -" for ( n = total_bytes % sizeof( int32_t ); n > 0; n-- )\r\n" -" {\r\n" -" if ( *ptr8++ != (char) fill_value )\r\n" -" {\r\n" -" total_bytes_used++;\r\n" -" }\r\n" -"\r\n" -" /* Update Value */\r\n" -" fill_value >>= 8;\r\n" -" }\r\n" -"\r\n" -" return total_bytes_used;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * mem_check_OOB()\r\n" -" *\r\n" -" * Checks, if out-of-bounds access has occured. This is done by inspecting the 'signature' value\r\n" -" * taht has been added before and after the memory block during its allocation\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static unsigned int mem_check_OOB( allocator_record *record_ptr )\r\n" -"{\r\n" -" int32_t *ptr32;\r\n" -" unsigned int OOB_Flag = 0x0;\r\n" -" int32_t mask;\r\n" -" size_t i;\r\n" -" int f;\r\n" -"\r\n" -" ptr32 = (int32_t *) record_ptr->block_ptr - N_32BITS_BLOCKS;\r\n" -"\r\n" -" /* Check the Signature at the Beginning of Memory Block */\r\n" -" i = N_32BITS_BLOCKS;\r\n" -" do\r\n" -" {\r\n" -" if ( *ptr32++ ^ MAGIC_VALUE_OOB )\r\n" -" {\r\n" -" OOB_Flag |= OOB_START;\r\n" -" }\r\n" -" } while ( --i );\r\n" -"\r\n" -" /* Advance to End (Snap to lowest 32 Bits) */\r\n" -" ptr32 += record_ptr->block_size / sizeof( int32_t );\r\n" -"\r\n" -" /* Calculate Unused Space That has been added to get to the rounded Block Size */\r\n" -" i = ROUND_BLOCK_SIZE( record_ptr->block_size ) - record_ptr->block_size;\r\n" -"\r\n" -" /* Partial Check of Signature at the End of Memory Block (for block size that has been rounded) */\r\n" -" f = i % sizeof( int32_t );\r\n" -" if ( f != 0 )\r\n" -" {\r\n" -" mask = 0xFFFFFFFF << ( ( sizeof( int32_t ) - f ) * 8 );\r\n" -" if ( ( *ptr32++ ^ MAGIC_VALUE_OOB ) & mask )\r\n" -" {\r\n" -" OOB_Flag |= OOB_END;\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Full Check of Signature at the End of Memory Block, i.e. all 32 Bits (for the remainder after rounding) */\r\n" -" i /= sizeof( int32_t );\r\n" -" i += N_32BITS_BLOCKS;\r\n" -" do\r\n" -" {\r\n" -" if ( *ptr32++ ^ MAGIC_VALUE_OOB )\r\n" -" {\r\n" -" OOB_Flag |= OOB_END;\r\n" -" }\r\n" -" } while ( --i );\r\n" -"\r\n" -" return OOB_Flag;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * malloc_hash()\r\n" -" *\r\n" -" * Calculate hash from function name, line number and malloc size\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static unsigned long malloc_hash( const char *func_name, int func_lineno, char *size_str )\r\n" -"{\r\n" -" unsigned long hash = 5381;\r\n" -" const char *ptr_str;\r\n" -"\r\n" -" ptr_str = func_name;\r\n" -" while ( ptr_str != NULL && *ptr_str != '\\0' )\r\n" -" {\r\n" -" hash = ( ( hash << 5 ) + hash ) + *ptr_str++; /* hash * 33 + char */\r\n" -" }\r\n" -"\r\n" -" hash = ( ( hash << 5 ) + hash ) + func_lineno; /* hash * 33 + func_lineno */\r\n" -"\r\n" -" ptr_str = size_str;\r\n" -" while ( ptr_str != NULL && *ptr_str != '\\0' )\r\n" -" {\r\n" -" hash = ( ( hash << 5 ) + hash ) + *ptr_str++; /* hash * 33 + char */\r\n" -" }\r\n" -"\r\n" -" return hash;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * get_mem_record()\r\n" -" *\r\n" -" * Search for memory record in the internal list, return NULL if not found\r\n" -" * Start from index_record\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"allocator_record *get_mem_record( unsigned long *hash, const char *func_name, int func_lineno, char *size_str, int *index_record )\r\n" -"{\r\n" -" int i;\r\n" -"\r\n" -" if ( *index_record < 0 || *index_record > Num_Records )\r\n" -" {\r\n" -" return NULL;\r\n" -" }\r\n" -"\r\n" -" /* calculate hash */\r\n" -" *hash = malloc_hash( func_name, func_lineno, size_str );\r\n" -"\r\n" -" for ( i = *index_record; i < Num_Records; i++ )\r\n" -" {\r\n" -" /* check, if memory block is not allocated at the moment and the hash matches */\r\n" -" if ( allocation_list[i].block_ptr == NULL && *hash == allocation_list[i].hash )\r\n" -" {\r\n" -" *index_record = i;\r\n" -" return &( allocation_list[i] );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* not found */\r\n" -" *index_record = -1;\r\n" -" return NULL;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * mem_free()\r\n" -" *\r\n" -" * This function de-allocatesd the memory block and frees the mphysical memory with free().\r\n" -" * It also updates actual and average usage of the memory block.\r\n" -" *\r\n" -" * Note: The record is not removed from the list and may be reused later on in mem_alloc()!\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void mem_free( const char *func_name, int func_lineno, void *ptr )\r\n" -"{\r\n" -" int i, index_record;\r\n" -" char *tmp_ptr;\r\n" -" allocator_record *ptr_record;\r\n" -"\r\n" -" /* Search for the Block Pointer in the List */\r\n" -" ptr_record = NULL;\r\n" -" index_record = -1;\r\n" -" for ( i = 0; i < Num_Records; i++ )\r\n" -" {\r\n" -" if ( ptr == allocation_list[i].block_ptr )\r\n" -" { /* Yes, Found it */\r\n" -" ptr_record = &( allocation_list[i] );\r\n" -" index_record = i;\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" if ( ptr_record == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Error: Unable to Find Record Corresponding to the Allocated Memory Block!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* Update the Heap Size */\r\n" -" current_heap_size -= ptr_record->block_size;\r\n" -"\r\n" -" /* Calculate the Actual Usage of the Memory Block (Look for Signature) */\r\n" -" ptr_record->total_used_size += mem_set_usage( ptr_record );\r\n" -"\r\n" -" /* Check, if Out-Of-Bounds Access has been Detected */\r\n" -" ptr_record->OOB_Flag = mem_check_OOB( ptr_record );\r\n" -"\r\n" -" /* De-Allocate Memory Block */\r\n" -" tmp_ptr = (char *) ptr;\r\n" -" tmp_ptr -= BLOCK_ROUNDING;\r\n" -" ptr = (void *) tmp_ptr;\r\n" -" free( ptr );\r\n" -"\r\n" -" /* Add new entry to the heap allocation call tree */\r\n" -" if ( heap_allocation_call_tree == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"Error: Heap allocation call tree not created!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -"\r\n" -" /* check, if the maximum size of the call tree has been reached -> resize if so */\r\n" -" if ( heap_allocation_call_tree_size >= heap_allocation_call_tree_max_size )\r\n" -" {\r\n" -" heap_allocation_call_tree_max_size += MAX_NUM_RECORDS_REALLOC_STEP;\r\n" -" heap_allocation_call_tree = (int *) realloc( heap_allocation_call_tree, heap_allocation_call_tree_max_size * sizeof( int ) );\r\n" -" }\r\n" -"\r\n" -" heap_allocation_call_tree[heap_allocation_call_tree_size++] = -index_record;\r\n" -"\r\n" -" /* Reset memory block pointer (this is checked when updating wc intra-frame and inter-frame memory) */\r\n" -" ptr_record->block_ptr = NULL;\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * update_mem()\r\n" -" *\r\n" -" * This function updates the worst-case intra-frame memory and the worst-case inter-frame memory.\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void update_mem( void )\r\n" -"{\r\n" -" int i, j, flag_alloc = -1, i_record;\r\n" -" int32_t size_current_intra_frame_heap;\r\n" -" int *list_current_intra_frame_heap = NULL, n_items_current_intra_frame_heap;\r\n" -" allocator_record *ptr_record;\r\n" -"\r\n" -" /* process the heap allocation call tree */\r\n" -" n_items_current_intra_frame_heap = 0;\r\n" -" size_current_intra_frame_heap = 0;\r\n" -" for ( i = 0; i < heap_allocation_call_tree_size; i++ )\r\n" -" {\r\n" -" /* get the record */\r\n" -" i_record = heap_allocation_call_tree[i];\r\n" -"\r\n" -" if ( i_record > 0 )\r\n" -" {\r\n" -" flag_alloc = 1;\r\n" -" }\r\n" -" else if ( i_record < 0 )\r\n" -" {\r\n" -" flag_alloc = 0;\r\n" -" i_record = -i_record;\r\n" -" }\r\n" -" ptr_record = &( allocation_list[i_record] );\r\n" -"\r\n" -" if ( ptr_record->frame_allocated == update_cnt && ptr_record->block_ptr == NULL )\r\n" -" {\r\n" -" /* intra-frame heap memory */\r\n" -" if ( list_current_intra_frame_heap == NULL )\r\n" -" {\r\n" -" list_current_intra_frame_heap = (int *) malloc( heap_allocation_call_tree_size * sizeof( int ) );\r\n" -" memset( list_current_intra_frame_heap, -1, heap_allocation_call_tree_size * sizeof( int ) );\r\n" -" }\r\n" -"\r\n" -" /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */\r\n" -" if ( i_record == 0 )\r\n" -" {\r\n" -" flag_alloc = 1;\r\n" -" for ( j = 0; j < n_items_current_intra_frame_heap; j++ )\r\n" -" {\r\n" -" if ( list_current_intra_frame_heap[j] == i_record )\r\n" -" {\r\n" -" flag_alloc = 0;\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" if ( flag_alloc )\r\n" -" {\r\n" -" /* add to list */\r\n" -" list_current_intra_frame_heap[n_items_current_intra_frame_heap++] = i_record;\r\n" -" size_current_intra_frame_heap += ptr_record->block_size;\r\n" -"\r\n" -" /* check, if this is the new worst-case */\r\n" -" if ( size_current_intra_frame_heap > size_wc_intra_frame_heap )\r\n" -" {\r\n" -" if ( n_items_current_intra_frame_heap >= max_items_wc_intra_frame_heap )\r\n" -" {\r\n" -" /* resize list, if needed */\r\n" -" max_items_wc_intra_frame_heap = n_items_current_intra_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;\r\n" -" list_wc_intra_frame_heap = realloc( list_wc_intra_frame_heap, max_items_wc_intra_frame_heap * sizeof( int ) );\r\n" -" }\r\n" -"\r\n" -" /* save to wc list */\r\n" -" memmove( list_wc_intra_frame_heap, list_current_intra_frame_heap, n_items_current_intra_frame_heap * sizeof( int ) );\r\n" -" n_items_wc_intra_frame_heap = n_items_current_intra_frame_heap;\r\n" -" size_wc_intra_frame_heap = size_current_intra_frame_heap;\r\n" -" location_wc_intra_frame_heap = update_cnt;\r\n" -" ptr_record->wc_heap_size_intra_frame = ptr_record->block_size;\r\n" -" }\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" /* remove from list */\r\n" -" for ( j = 0; j < n_items_current_intra_frame_heap; j++ )\r\n" -" {\r\n" -" if ( list_current_intra_frame_heap[j] == i_record )\r\n" -" {\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -" memmove( &list_current_intra_frame_heap[j], &list_current_intra_frame_heap[j + 1], ( n_items_current_intra_frame_heap - j ) * sizeof( int ) );\r\n" -" n_items_current_intra_frame_heap--;\r\n" -" size_current_intra_frame_heap -= ptr_record->block_size;\r\n" -"\r\n" -" /* reset block size */\r\n" -" ptr_record->frame_allocated = -1;\r\n" -" ptr_record->block_size = 0;\r\n" -" }\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" /* inter-frame heap memory */\r\n" -"\r\n" -" /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */\r\n" -" if ( i_record == 0 )\r\n" -" {\r\n" -" flag_alloc = 1;\r\n" -" for ( j = 0; j < n_items_current_inter_frame_heap; j++ )\r\n" -" {\r\n" -" if ( list_current_inter_frame_heap[j] == i_record )\r\n" -" {\r\n" -" flag_alloc = 0;\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" if ( flag_alloc )\r\n" -" {\r\n" -" /* add to list */\r\n" -" if ( n_items_current_inter_frame_heap >= max_items_current_inter_frame_heap )\r\n" -" {\r\n" -" /* resize list, if needed */\r\n" -" max_items_current_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;\r\n" -" list_current_inter_frame_heap = realloc( list_current_inter_frame_heap, max_items_current_inter_frame_heap * sizeof( int ) );\r\n" -" }\r\n" -"\r\n" -" list_current_inter_frame_heap[n_items_current_inter_frame_heap++] = i_record;\r\n" -" size_current_inter_frame_heap += ptr_record->block_size;\r\n" -"\r\n" -" /* check, if this is the new worst-case */\r\n" -" if ( size_current_inter_frame_heap > size_wc_inter_frame_heap )\r\n" -" {\r\n" -" if ( n_items_current_inter_frame_heap >= max_items_wc_inter_frame_heap )\r\n" -" {\r\n" -" /* resize list, if needed */\r\n" -" max_items_wc_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;\r\n" -" list_wc_inter_frame_heap = realloc( list_wc_inter_frame_heap, max_items_wc_inter_frame_heap * sizeof( int ) );\r\n" -" }\r\n" -"\r\n" -" memmove( list_wc_inter_frame_heap, list_current_inter_frame_heap, n_items_current_inter_frame_heap * sizeof( int ) );\r\n" -" n_items_wc_inter_frame_heap = n_items_current_inter_frame_heap;\r\n" -" size_wc_inter_frame_heap = size_current_inter_frame_heap;\r\n" -" location_wc_inter_frame_heap = update_cnt;\r\n" -" ptr_record->wc_heap_size_inter_frame = ptr_record->block_size;\r\n" -" }\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" /* remove from list */\r\n" -" for ( j = 0; j < n_items_current_inter_frame_heap; j++ )\r\n" -" {\r\n" -" if ( list_current_inter_frame_heap[j] == i_record )\r\n" -" {\r\n" -" break;\r\n" -" }\r\n" -" }\r\n" -" memmove( &list_current_inter_frame_heap[j], &list_current_inter_frame_heap[j + 1], ( n_items_current_inter_frame_heap - j ) * sizeof( int ) );\r\n" -" n_items_current_inter_frame_heap--;\r\n" -" size_current_inter_frame_heap -= ptr_record->block_size;\r\n" -"\r\n" -" /* reset block size */\r\n" -" ptr_record->frame_allocated = -1;\r\n" -" ptr_record->block_size = 0;\r\n" -" }\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* reset heap allocation call tree */\r\n" -" heap_allocation_call_tree_size = 0;\r\n" -"\r\n" -" if ( list_current_intra_frame_heap )\r\n" -" {\r\n" -" free( list_current_intra_frame_heap );\r\n" -" }\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"#ifdef MEM_COUNT_DETAILS\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * subst()\r\n" -" *\r\n" -" * Substitute character in string\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static void subst( char *s, char from, char to )\r\n" -"{\r\n" -" while ( *s == from )\r\n" -" {\r\n" -" *s++ = to;\r\n" -" }\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * mem_count_summary()\r\n" -" *\r\n" -" * Print detailed (per-item) information about heap memory usage\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"static void mem_count_summary( void )\r\n" -"{\r\n" -" int i, j, index, index_record;\r\n" -" size_t length;\r\n" -" char buf[300], format_str[50], name_str[MAX_FUNCTION_NAME_LENGTH + 3], parms_str[MAX_PARAMS_LENGTH + 1], type_str[10], usage_str[20], size_str[20], line_str[10];\r\n" -" allocator_record *ptr_record, *ptr;\r\n" -"\r\n" -" /* Prepare format string */\r\n" -" sprintf( format_str, \"%%-%ds %%5s %%6s %%-%ds %%20s %%6s \", MAX_FUNCTION_NAME_LENGTH, MAX_PARAMS_LENGTH );\r\n" -"\r\n" -" if ( n_items_wc_intra_frame_heap > 0 )\r\n" -" {\r\n" -" /* Intra-Frame Heap Size */\r\n" -" fprintf( stdout, \"\\nList of memory blocks when maximum intra-frame heap size is reached:\\n\\n\" );\r\n" -"\r\n" -" /* Find duplicate records (same hash and worst-case heap size) */\r\n" -" for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )\r\n" -" {\r\n" -" index_record = list_wc_intra_frame_heap[i];\r\n" -" if ( index_record == -1 )\r\n" -" {\r\n" -" continue;\r\n" -" }\r\n" -"\r\n" -" ptr_record = &( allocation_list[index_record] );\r\n" -" for ( j = i + 1; j < n_items_wc_intra_frame_heap; j++ )\r\n" -" {\r\n" -" index = list_wc_intra_frame_heap[j];\r\n" -" if ( index == -1 )\r\n" -" {\r\n" -" continue;\r\n" -" }\r\n" -" ptr = &( allocation_list[index] );\r\n" -"\r\n" -" if ( ptr->hash == ptr_record->hash && ptr->wc_heap_size_intra_frame == ptr_record->wc_heap_size_intra_frame )\r\n" -" {\r\n" -" ptr_record->noccurances++;\r\n" -" list_wc_intra_frame_heap[j] = -1;\r\n" -" }\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Print Header */\r\n" -" sprintf( buf, format_str, \"Function Name\", \"Line\", \"Type\", \"Function Parameters\", \"Maximum Size\", \"Usage\" );\r\n" -" puts( buf );\r\n" -" length = strlen( buf );\r\n" -" sprintf( buf, \"%0*d\\n\", (int) length - 1, 0 );\r\n" -" subst( buf, '0', '-' );\r\n" -" puts( buf );\r\n" -"\r\n" -" for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )\r\n" -" {\r\n" -" index_record = list_wc_intra_frame_heap[i];\r\n" -"\r\n" -" if ( index_record != -1 )\r\n" -" {\r\n" -" /* get the record */\r\n" -" ptr_record = &( allocation_list[index_record] );\r\n" -"\r\n" -" /* prepare information strings */\r\n" -" strncpy( name_str, ptr_record->name, MAX_FUNCTION_NAME_LENGTH );\r\n" -" strcat( name_str, \"()\" );\r\n" -" name_str[MAX_FUNCTION_NAME_LENGTH] = '\\0';\r\n" -" strncpy( parms_str, &( ptr_record->params[2] ), MAX_PARAMS_LENGTH );\r\n" -" parms_str[MAX_PARAMS_LENGTH] = '\\0';\r\n" -"\r\n" -" if ( ptr_record->params[0] == 'm' )\r\n" -" {\r\n" -" strcpy( type_str, \"malloc\" );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" strcpy( type_str, \"calloc\" );\r\n" -" }\r\n" -"\r\n" -" sprintf( line_str, \"%d\", ptr_record->lineno );\r\n" -"\r\n" -" /* prepare average usage & memory size strings */\r\n" -" sprintf( usage_str, \"%d%%\", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 1 ) ) * 100.0f ) );\r\n" -"\r\n" -" if ( ptr_record->noccurances > 1 )\r\n" -" {\r\n" -" sprintf( size_str, \"%dx%d %s\", ptr_record->noccurances, (int) ( ( ptr_record->noccurances * ptr_record->wc_heap_size_intra_frame ) >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" sprintf( size_str, \"%d %s\", (int) ( ptr_record->wc_heap_size_intra_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -"\r\n" -" sprintf( buf, format_str, name_str, line_str, type_str, parms_str, size_str, usage_str );\r\n" -" puts( buf );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, \"\\n\" );\r\n" -" }\r\n" -"\r\n" -" if ( n_items_wc_inter_frame_heap > 0 )\r\n" -" {\r\n" -" /* Inter-Frame Heap Size */\r\n" -" fprintf( stdout, \"\\nList of memory blocks when maximum inter-frame heap size is reached:\\n\\n\" );\r\n" -"\r\n" -" /* Find duplicate records (same hash and worst-case heap size) */\r\n" -" for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )\r\n" -" {\r\n" -" index_record = list_wc_inter_frame_heap[i];\r\n" -" if ( index_record == -1 )\r\n" -" {\r\n" -" continue;\r\n" -" }\r\n" -" ptr_record = &( allocation_list[index_record] );\r\n" -" ptr_record->noccurances = 1; /* reset the counter because som blocks may be both, intra-frame and inter-frame */\r\n" -" for ( j = i + 1; j < n_items_wc_inter_frame_heap; j++ )\r\n" -" {\r\n" -" index = list_wc_inter_frame_heap[j];\r\n" -" if ( index == -1 )\r\n" -" {\r\n" -" continue;\r\n" -" }\r\n" -" ptr = &( allocation_list[index] );\r\n" -"\r\n" -" if ( ptr->hash == ptr_record->hash && ptr->wc_heap_size_inter_frame == ptr_record->wc_heap_size_inter_frame )\r\n" -" {\r\n" -" ptr_record->noccurances++;\r\n" -" list_wc_inter_frame_heap[j] = -1;\r\n" -" }\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Print Header */\r\n" -" sprintf( buf, format_str, \"Function Name\", \"Line\", \"Type\", \"Function Parameters\", \"Maximum Size\", \"Usage\" );\r\n" -" puts( buf );\r\n" -" length = strlen( buf );\r\n" -" sprintf( buf, \"%0*d\\n\", (int) length - 1, 0 );\r\n" -" subst( buf, '0', '-' );\r\n" -" puts( buf );\r\n" -"\r\n" -" for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )\r\n" -" {\r\n" -" index_record = list_wc_inter_frame_heap[i];\r\n" -"\r\n" -" if ( index_record != -1 )\r\n" -" {\r\n" -" /* get the record */\r\n" -" ptr_record = &( allocation_list[index_record] );\r\n" -"\r\n" -" /* prepare information strings */\r\n" -" strncpy( name_str, ptr_record->name, MAX_FUNCTION_NAME_LENGTH );\r\n" -" strcat( name_str, \"()\" );\r\n" -" name_str[MAX_FUNCTION_NAME_LENGTH] = '\\0';\r\n" -" strncpy( parms_str, &( ptr_record->params[2] ), MAX_PARAMS_LENGTH );\r\n" -" parms_str[MAX_PARAMS_LENGTH] = '\\0';\r\n" -"\r\n" -" if ( ptr_record->params[0] == 'm' )\r\n" -" {\r\n" -" strcpy( type_str, \"malloc\" );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" strcpy( type_str, \"calloc\" );\r\n" -" }\r\n" -"\r\n" -" sprintf( line_str, \"%d\", ptr_record->lineno );\r\n" -"\r\n" -" /* prepare average usage & memory size strings */\r\n" -" sprintf( usage_str, \"%d%%\", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 1 ) ) * 100.0f ) );\r\n" -"\r\n" -" if ( ptr_record->noccurances > 1 )\r\n" -" {\r\n" -" sprintf( size_str, \"%dx%d %s\", ptr_record->noccurances, (int) ( ( ptr_record->noccurances * ptr_record->wc_heap_size_inter_frame ) >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" sprintf( size_str, \"%d %s\", (int) ( ptr_record->wc_heap_size_inter_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -"\r\n" -" sprintf( buf, format_str, name_str, line_str, type_str, parms_str, size_str, usage_str );\r\n" -" puts( buf );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, \"\\n\" );\r\n" -" }\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * export_mem()\r\n" -" *\r\n" -" * Export detailed (per-item) information about heap memory usage to a .csv file\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void export_mem( const char *csv_filename )\r\n" -"{\r\n" -" int i;\r\n" -" static FILE *fid = NULL;\r\n" -" allocator_record *record_ptr;\r\n" -"\r\n" -" if ( csv_filename == NULL || strcmp( csv_filename, \"\" ) == 0 )\r\n" -" {\r\n" -" return;\r\n" -" }\r\n" -"\r\n" -" /* Check, if the .csv file has already been opened */\r\n" -" if ( fid == NULL )\r\n" -" {\r\n" -" fid = fopen( csv_filename, \"wb\" );\r\n" -"\r\n" -" if ( fid == NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"\\nCannot open %s!\\n\\n\", csv_filename );\r\n" -" exit( -1 );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" /* Export individual heap memory records to a .csv file */\r\n" -" for ( i = 0; i < Num_Records; i++ )\r\n" -" {\r\n" -" record_ptr = &( allocation_list[i] );\r\n" -" fprintf( fid, \"%s:%d,%d;\", record_ptr->name, record_ptr->lineno, record_ptr->block_size );\r\n" -" }\r\n" -" fprintf( fid, \"\\n\" );\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"#endif\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * print_mem()\r\n" -" *\r\n" -" * Print information about ROM and RAM memory usage\r\n" -" *--------------------------------------------------------------------*/\r\n" -"\r\n" -"void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] )\r\n" -"{\r\n" -" int i, nElem;\r\n" -"\r\n" -" fprintf( stdout, \"\\n\\n --- Memory usage --- \\n\\n\" );\r\n" -"\r\n" -" if ( Const_Data_PROM_Table != NULL )\r\n" -" {\r\n" -" nElem = 0;\r\n" -" while ( strcmp( Const_Data_PROM_Table[nElem].file_spec, \"\" ) != 0 )\r\n" -" nElem++;\r\n" -"\r\n" -" for ( i = 0; i < nElem; i++ )\r\n" -" {\r\n" -" fprintf( stdout, \"Program ROM size (%s): %d instruction words\\n\", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size );\r\n" -" }\r\n" -"\r\n" -" for ( i = 0; i < nElem; i++ )\r\n" -" {\r\n" -" if ( Const_Data_PROM_Table[i].Get_Const_Data_Size_Func == NULL )\r\n" -" {\r\n" -" fprintf( stdout, \"Error: Cannot retrieve or calculate Table ROM size of (%s)!\\n\", Const_Data_PROM_Table[i].file_spec );\r\n" -" }\r\n" -"\r\n" -" fprintf( stdout, \"Table ROM (const data) size (%s): %d %s\\n\", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].Get_Const_Data_Size_Func() >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );\r\n" -" }\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" fprintf( stdout, \"Program ROM size: not available\\n\" );\r\n" -" fprintf( stdout, \"Table ROM (const data) size: not available\\n\" );\r\n" -" }\r\n" -"\r\n" -" if ( wc_ram_size > 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum RAM (stack + heap) size: %d %s in frame %d\\n\", wc_ram_size >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size], wc_ram_frame );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum RAM (stack + heap) size: not available\\n\" );\r\n" -" }\r\n" -"\r\n" -" /* check, if the stack is empty */\r\n" -" if ( ptr_current_stack != ptr_base_stack )\r\n" -" {\r\n" -" fprintf( stderr, \"Warning: Stack is not empty.\\n\" );\r\n" -" }\r\n" -"\r\n" -" if ( ptr_base_stack - ptr_max_stack > 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum stack size: %lu %s in frame %d\\n\", ( ( ptr_base_stack - ptr_max_stack ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size],\r\n" -" wc_stack_frame );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum stack size: not available\\n\" );\r\n" -" }\r\n" -"\r\n" -" /* last update of intra-frame memory and inter-frame memory, if needed */\r\n" -" if ( heap_allocation_call_tree_size > 0 )\r\n" -" {\r\n" -" update_mem();\r\n" -" }\r\n" -"\r\n" -" /* check, if all memory blocks have been deallocated (freed) */\r\n" -" for ( i = 0; i < Num_Records; i++ )\r\n" -" {\r\n" -" if ( allocation_list[i].block_ptr != NULL )\r\n" -" {\r\n" -" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", allocation_list[i].name, allocation_list[i].lineno, \"Error: Memory Block has not been De-Allocated with free()!\" );\r\n" -" exit( -1 );\r\n" -" }\r\n" -" }\r\n" -"\r\n" -" if ( n_items_wc_intra_frame_heap > 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum intra-frame heap size: %d %s in frame %d\\n\", size_wc_intra_frame_heap >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size], location_wc_intra_frame_heap );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum intra-frame heap size: 0\\n\" );\r\n" -" }\r\n" -"\r\n" -" if ( n_items_wc_inter_frame_heap > 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum inter-frame heap size: %d %s in frame %d\\n\", size_wc_inter_frame_heap >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size], location_wc_inter_frame_heap );\r\n" -" }\r\n" -" else\r\n" -" {\r\n" -" fprintf( stdout, \"Maximum inter-frame heap size: 0\\n\" );\r\n" -" }\r\n" -"\r\n" -"#ifdef MEM_COUNT_DETAILS\r\n" -" /* Print detailed information about worst-case stack usage */\r\n" -" if ( ptr_base_stack - ptr_max_stack > 0 )\r\n" -" {\r\n" -" print_stack_call_tree();\r\n" -" }\r\n" -"\r\n" -" /* Print detailed information about worst-case heap usage */\r\n" -" mem_count_summary();\r\n" -"#endif\r\n" -"\r\n" -" if ( Stat_Cnt_Size > 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"\\nNote: 1 word = %d bits\\n\", 8 << Stat_Cnt_Size );\r\n" -" fprintf( stdout, \"This is an optimistic estimate of memory consumption assuming that each variable type is stored with sizeof(type) bits\\n\" );\r\n" -" }\r\n" -"\r\n" -" if ( n_items_wc_intra_frame_heap > 0 )\r\n" -" {\r\n" -" fprintf( stdout, \"Intra-frame heap memory is allocated and de-allocated in the same frame\\n\" );\r\n" -" }\r\n" -"\r\n" -" /* De-allocate list of heap memory blocks */\r\n" -" if ( allocation_list != NULL )\r\n" -" {\r\n" -" free( allocation_list );\r\n" -" }\r\n" -"\r\n" -" /* De-allocate heap allocation call tree */\r\n" -" if ( heap_allocation_call_tree != NULL )\r\n" -" {\r\n" -" free( heap_allocation_call_tree );\r\n" -" }\r\n" -"\r\n" -" /* De-allocate intra-frame and inter-frame heap lists */\r\n" -" if ( list_wc_intra_frame_heap != NULL )\r\n" -" {\r\n" -" free( list_wc_intra_frame_heap );\r\n" -" }\r\n" -"\r\n" -" if ( list_current_inter_frame_heap != NULL )\r\n" -" {\r\n" -" free( list_current_inter_frame_heap );\r\n" -" }\r\n" -"\r\n" -" if ( list_wc_inter_frame_heap != NULL )\r\n" -" {\r\n" -" free( list_wc_inter_frame_heap );\r\n" -" }\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"#endif /* WMOPS */\r\n" -"\r\n" -"#ifndef WMOPS\r\n" -"int cntr_push_pop = 0; /* global counter for checking balanced push_wmops()/pop_wmops() pairs when WMOPS is not activated */\r\n" -"#endif\r\n" -"\r\n" \ No newline at end of file +"/*\r\n", +" * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved.\r\n", +" *\r\n", +" * This software is protected by copyright law and by international treaties. The source code, and all of its derivations,\r\n", +" * is provided by VoiceAge Corporation under the \"ITU-T Software Tools' General Public License\". Please, read the license file\r\n", +" * or refer to ITU-T Recommendation G.191 on \"SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS\".\r\n", +" *\r\n", +" * Any use of this software is permitted provided that this notice is not removed and that neither the authors nor\r\n", +" * VoiceAge Corporation are deemed to have made any representations as to the suitability of this software\r\n", +" * for any purpose nor are held responsible for any defects of this software. THERE IS NO WARRANTY FOR THIS SOFTWARE.\r\n", +" *\r\n", +" * Authors: Guy Richard, Vladimir Malenovsky (Vladimir.Malenovsky@USherbrooke.ca)\r\n", +" */\r\n", +"\r\n", +"#include \r\n", +"#include \r\n", +"#include \r\n", +"#include \r\n", +"#include \r\n", +"\r\n", +"#ifndef _MSC_VER\r\n", +"#include \r\n", +"#include \r\n", +"#else\r\n", +"#include \r\n", +"#endif\r\n", +"\r\n", +"#include \"options.h\"\r\n", +"#include \"wmc_auto.h\"\r\n", +"\r\n", +"#define WMC_TOOL_SKIP /* Skip the instrumentation of this file, if invoked by accident */\r\n", +"\r\n", +"#ifdef WMOPS\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * Complexity counting tool\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"#define MAX_FUNCTION_NAME_LENGTH 50 /* Maximum length of the function name */\r\n", +"#define MAX_PARAMS_LENGTH 50 /* Maximum length of the function parameter string */\r\n", +"#define MAX_NUM_RECORDS 300 /* Initial maximum number of records -> mightb be increased during runtime, if needed */\r\n", +"#define MAX_NUM_RECORDS_REALLOC_STEP 50 /* When re-allocating the list of records, increase the number of records by this number */\r\n", +"#define MAX_CALL_TREE_DEPTH 100 /* maximum depth of the function call tree */\r\n", +"#define DOUBLE_MAX 0x80000000\r\n", +"#define FAC ( FRAMES_PER_SECOND / 1e6 )\r\n", +"\r\n", +"\r\n", +"typedef struct \r\n", +"{\r\n", +" char label[MAX_FUNCTION_NAME_LENGTH];\r\n", +" long call_number;\r\n", +" long update_cnt;\r\n", +" int call_tree[MAX_CALL_TREE_DEPTH];\r\n", +" long LastWOper;\r\n", +" double start_selfcnt;\r\n", +" double current_selfcnt;\r\n", +" double max_selfcnt;\r\n", +" double min_selfcnt;\r\n", +" double tot_selfcnt;\r\n", +" double start_cnt; \r\n", +" double current_cnt;\r\n", +" double max_cnt;\r\n", +" double min_cnt;\r\n", +" double tot_cnt;\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" int32_t current_call_number;\r\n", +" double wc_cnt;\r\n", +" double wc_selfcnt;\r\n", +" int32_t wc_call_number;\r\n", +"#endif\r\n", +"} wmops_record;\r\n", +"\r\n", +"double ops_cnt;\r\n", +"double prom_cnt;\r\n", +"double inst_cnt[NUM_INST];\r\n", +"\r\n", +"static wmops_record *wmops = NULL;\r\n", +"static int num_wmops_records, max_num_wmops_records;\r\n", +"static int current_record;\r\n", +"static long update_cnt;\r\n", +"static double start_cnt;\r\n", +"static double max_cnt;\r\n", +"static double min_cnt;\r\n", +"static double inst_cnt_wc[NUM_INST];\r\n", +"static long fnum_cnt_wc;\r\n", +"static int *wmops_caller_stack = NULL, wmops_caller_stack_index, max_wmops_caller_stack_index = 0;\r\n", +"static int *heap_allocation_call_tree = NULL, heap_allocation_call_tree_size = 0, heap_allocation_call_tree_max_size = 0;\r\n", +"\r\n", +"void reset_wmops( void )\r\n", +"{\r\n", +" int i, j;\r\n", +" unsigned int *ptr;\r\n", +"\r\n", +" num_wmops_records = 0;\r\n", +" max_num_wmops_records = MAX_NUM_RECORDS;\r\n", +" current_record = -1;\r\n", +" update_cnt = 0;\r\n", +"\r\n", +" max_cnt = 0.0;\r\n", +" min_cnt = DOUBLE_MAX;\r\n", +" start_cnt = 0.0;\r\n", +" ops_cnt = 0.0;\r\n", +"\r\n", +" /* allocate the list of wmops records */\r\n", +" if ( wmops == NULL )\r\n", +" {\r\n", +" wmops = (wmops_record *)malloc( max_num_wmops_records * sizeof( wmops_record ) );\r\n", +" }\r\n", +"\r\n", +" if ( wmops == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Unable to Allocate List of WMOPS Records!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* allocate the BASOP WMOPS counter */\r\n", +" if ( multiCounter == NULL )\r\n", +" {\r\n", +" multiCounter = (BASIC_OP *) malloc( max_num_wmops_records * sizeof( BASIC_OP ) );\r\n", +" }\r\n", +"\r\n", +" if ( multiCounter == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Unable to Allocate the BASOP WMOPS counter!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* initilize the list of wmops records */\r\n", +" /* initilize the BASOP WMOPS counters */\r\n", +" for ( i = 0; i < max_num_wmops_records; i++ )\r\n", +" {\r\n", +" strcpy( &wmops[i].label[0], \"\\0\" );\r\n", +" wmops[i].call_number = 0;\r\n", +" wmops[i].update_cnt = 0;\r\n", +" for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ )\r\n", +" {\r\n", +" wmops[i].call_tree[j] = -1;\r\n", +" }\r\n", +" wmops[i].start_selfcnt = 0.0;\r\n", +" wmops[i].current_selfcnt = 0.0;\r\n", +" wmops[i].max_selfcnt = 0.0;\r\n", +" wmops[i].min_selfcnt = DOUBLE_MAX;\r\n", +" wmops[i].tot_selfcnt = 0.0;\r\n", +" wmops[i].start_cnt = 0.0;\r\n", +" wmops[i].current_cnt = 0.0;\r\n", +" wmops[i].max_cnt = 0.0;\r\n", +" wmops[i].min_cnt = DOUBLE_MAX;\r\n", +" wmops[i].tot_cnt = 0.0;\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" wmops[i].wc_cnt = 0.0;\r\n", +" wmops[i].wc_selfcnt = 0.0;\r\n", +" wmops[i].current_call_number = 0;\r\n", +" wmops[i].wc_call_number = -1;\r\n", +"#endif\r\n", +"\r\n", +" /* clear all BASOP operation counters */\r\n", +" ptr = (unsigned int*) &multiCounter[i];\r\n", +" for ( j = 0; j < (int) ( sizeof(BASIC_OP ) / sizeof( unsigned int ) ); j++ )\r\n", +" {\r\n", +" *ptr++ = 0;\r\n", +" }\r\n", +" wmops[i].LastWOper = 0;\r\n", +" }\r\n", +"\r\n", +" /* allocate the list of wmops callers to track the sequence of function calls */\r\n", +" wmops_caller_stack_index = 0;\r\n", +" max_wmops_caller_stack_index = MAX_NUM_RECORDS;\r\n", +" if ( wmops_caller_stack == NULL )\r\n", +" {\r\n", +" wmops_caller_stack = malloc( max_wmops_caller_stack_index * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" if ( wmops_caller_stack == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Unable to Allocate List of WMOPS Callers!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" for ( i = 0; i < max_wmops_caller_stack_index; i++ )\r\n", +" {\r\n", +" wmops_caller_stack[i] = -1;\r\n", +" }\r\n", +"\r\n", +" /* initialize auxiliary BASOP WMOPS variables */\r\n", +" call_occurred = 1;\r\n", +" funcId_where_last_call_to_else_occurred = INT_MAX;\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"void push_wmops( const char *label )\r\n", +"{\r\n", +" int new_flag;\r\n", +" int i, j;\r\n", +"\r\n", +" /* Check, if this is a new function label */\r\n", +" new_flag = 1;\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" if ( strcmp( wmops[i].label, label ) == 0 )\r\n", +" {\r\n", +" new_flag = 0;\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Create a new record in the list */\r\n", +" if ( new_flag )\r\n", +" {\r\n", +" if ( num_wmops_records >= max_num_wmops_records )\r\n", +" {\r\n", +" /* There is no room for a new wmops record -> reallocate the list */\r\n", +" max_num_wmops_records += MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" wmops = realloc( wmops, max_num_wmops_records * sizeof( wmops_record ) );\r\n", +" multiCounter = realloc( multiCounter, max_num_wmops_records * sizeof( BASIC_OP ) );\r\n", +" }\r\n", +"\r\n", +" strcpy( wmops[i].label, label );\r\n", +"\r\n", +" num_wmops_records++;\r\n", +" }\r\n", +"\r\n", +" /* Push the current context info to the new record */\r\n", +" if ( current_record >= 0 )\r\n", +" {\r\n", +" if ( wmops_caller_stack_index >= max_wmops_caller_stack_index )\r\n", +" {\r\n", +" /* There is no room for a new record -> reallocate the list */\r\n", +" max_wmops_caller_stack_index += MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" wmops_caller_stack = realloc( wmops_caller_stack, max_wmops_caller_stack_index * sizeof( int ) );\r\n", +" }\r\n", +" wmops_caller_stack[wmops_caller_stack_index++] = current_record;\r\n", +"\r\n", +" /* accumulate op counts */\r\n", +" wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt;\r\n", +"\r\n", +" /* update call tree */\r\n", +" for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ )\r\n", +" {\r\n", +" if ( wmops[i].call_tree[j] == current_record )\r\n", +" {\r\n", +" break;\r\n", +" }\r\n", +" else if ( wmops[i].call_tree[j] == -1 )\r\n", +" {\r\n", +" wmops[i].call_tree[j] = current_record;\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* update the current context info */\r\n", +" current_record = i;\r\n", +" wmops[current_record].start_selfcnt = ops_cnt;\r\n", +" wmops[current_record].start_cnt = ops_cnt;\r\n", +" wmops[current_record].call_number++;\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" wmops[current_record].current_call_number++;\r\n", +"#endif\r\n", +"\r\n", +" /* set the ID of BASOP functions counters */\r\n", +" Set_BASOP_WMOPS_counter( current_record );\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"void pop_wmops( void )\r\n", +"{\r\n", +" long tot;\r\n", +"\r\n", +" /* Check for underflow */\r\n", +" if ( current_record < 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"\\r pop_wmops(): stack underflow, too many calls to pop_wmops()\\n\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* add the BASOP complexity to the counter */\r\n", +" tot = DeltaWeightedOperation();\r\n", +" ops_cnt += tot;\r\n", +"\r\n", +" /* update count of current record */\r\n", +" wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt;\r\n", +" wmops[current_record].current_cnt += ops_cnt - wmops[current_record].start_cnt;\r\n", +"\r\n", +" /* Get back previous context from stack */\r\n", +" if ( wmops_caller_stack_index > 0 )\r\n", +" {\r\n", +" current_record = wmops_caller_stack[--wmops_caller_stack_index];\r\n", +" wmops[current_record].start_selfcnt = ops_cnt;\r\n", +"\r\n", +" /* set the ID of the previous BASOP counter */\r\n", +" Set_BASOP_WMOPS_counter( current_record );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" current_record = -1;\r\n", +" }\r\n", +"\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"void update_wmops( void )\r\n", +"{\r\n", +" int i;\r\n", +" double current_cnt;\r\n", +"#ifdef WMOPS_PER_FRAME\r\n", +" static FILE *fid = NULL;\r\n", +" const char filename[] = \"wmops_analysis\";\r\n", +" float tmpF;\r\n", +"#endif\r\n", +"\r\n", +" if ( wmops_caller_stack_index != 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"update_wmops(): WMOPS caller stack corrupted - check that all push_wmops() are matched with pop_wmops()!\\n\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +"#ifdef WMOPS_PER_FRAME\r\n", +" /* Check, if the output file has already been opened */\r\n", +" if ( fid == NULL )\r\n", +" {\r\n", +" fid = fopen( filename, \"wb\" );\r\n", +"\r\n", +" if ( fid == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"\\nCannot open %s!\\n\\n\", filename );\r\n", +" exit( -1 );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Write current complexity to the external file */\r\n", +" tmpF = (float) ( FAC * wmops[0].current_cnt );\r\n", +" fwrite( &tmpF, sizeof( float ), 1, fid );\r\n", +"#endif\r\n", +"\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" if ( ops_cnt - start_cnt > max_cnt )\r\n", +" {\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" wmops[i].wc_cnt = wmops[i].current_cnt;\r\n", +" wmops[i].wc_selfcnt = wmops[i].current_selfcnt;\r\n", +" wmops[i].wc_call_number = wmops[i].current_call_number;\r\n", +" }\r\n", +" }\r\n", +"#endif\r\n", +"\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" wmops[i].tot_selfcnt += wmops[i].current_selfcnt;\r\n", +" wmops[i].tot_cnt += wmops[i].current_cnt;\r\n", +"\r\n", +" if ( wmops[i].current_selfcnt > 0 )\r\n", +" {\r\n", +" if ( wmops[i].current_selfcnt > wmops[i].max_selfcnt )\r\n", +" {\r\n", +" wmops[i].max_selfcnt = wmops[i].current_selfcnt;\r\n", +" }\r\n", +"\r\n", +" if ( wmops[i].current_selfcnt < wmops[i].min_selfcnt )\r\n", +" {\r\n", +" wmops[i].min_selfcnt = wmops[i].current_selfcnt;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" wmops[i].current_selfcnt = 0;\r\n", +"\r\n", +" if ( wmops[i].current_cnt > 0 )\r\n", +" {\r\n", +" if ( wmops[i].current_cnt > wmops[i].max_cnt )\r\n", +" {\r\n", +" wmops[i].max_cnt = wmops[i].current_cnt;\r\n", +" }\r\n", +"\r\n", +"\r\n", +" if ( wmops[i].current_cnt < wmops[i].min_cnt )\r\n", +" {\r\n", +" wmops[i].min_cnt = wmops[i].current_cnt;\r\n", +" }\r\n", +"\r\n", +" wmops[i].update_cnt++;\r\n", +" }\r\n", +"\r\n", +" wmops[i].current_cnt = 0;\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" wmops[i].current_call_number = 0;\r\n", +"#endif\r\n", +"\r\n", +" /* update the WC of all BASOP counters */\r\n", +" Set_BASOP_WMOPS_counter( i );\r\n", +" Reset_BASOP_WMOPS_counter();\r\n", +" }\r\n", +"\r\n", +" current_cnt = ops_cnt - start_cnt;\r\n", +" if ( current_cnt > max_cnt )\r\n", +" {\r\n", +" max_cnt = current_cnt;\r\n", +"\r\n", +" for ( i = 0; i < NUM_INST; i++ )\r\n", +" {\r\n", +" inst_cnt_wc[i] = inst_cnt[i];\r\n", +" }\r\n", +"\r\n", +" fnum_cnt_wc = update_cnt + 1;\r\n", +" }\r\n", +"\r\n", +" if ( current_cnt < min_cnt )\r\n", +" {\r\n", +" min_cnt = current_cnt;\r\n", +" }\r\n", +"\r\n", +" for ( i = 0; i < NUM_INST; i++ )\r\n", +" {\r\n", +" inst_cnt[i] = 0.0;\r\n", +" }\r\n", +"\r\n", +" start_cnt = ops_cnt;\r\n", +"\r\n", +" /* increment frame counter */\r\n", +" update_cnt++;\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"void print_wmops( void )\r\n", +"{\r\n", +" int i, label_len, max_label_len;\r\n", +"\r\n", +" char *sfmts = \"%*s %8s %8s %7s %7s\\n\";\r\n", +" char *dfmts = \"%*s %8.2f %8.3f %7.3f %7.3f\\n\";\r\n", +" char *sfmt = \"%*s %8s %8s %7s %7s %7s %7s %7s\\n\";\r\n", +" char *dfmt = \"%*s %8.2f %8.3f %7.3f %7.3f %7.3f %7.3f %7.3f\\n\";\r\n", +"\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" int j;\r\n", +" char *sfmtt = \"%20s %4s %15s\\n\";\r\n", +" char *dfmtt = \"%20s %4d \";\r\n", +"#endif\r\n", +"\r\n", +" /* calculate maximum label length for compact prinout */\r\n", +" max_label_len = 0;\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" label_len = strlen( wmops[i].label );\r\n", +" if ( label_len > max_label_len )\r\n", +" {\r\n", +" max_label_len = label_len;\r\n", +" }\r\n", +" }\r\n", +" max_label_len += 4;\r\n", +"\r\n", +" fprintf( stdout, \"\\n\\n --- Complexity analysis [WMOPS] --- \\n\\n\" );\r\n", +" \r\n", +" fprintf( stdout, \"%*s %33s %23s\\n\", max_label_len, \"\", \"|------ SELF ------|\", \"|--- CUMULATIVE ---|\" );\r\n", +" fprintf( stdout, sfmt, max_label_len, \" routine\", \" calls\", \" min \", \" max \", \" avg \", \" min \", \" max \", \" avg \" );\r\n", +" fprintf( stdout, sfmt, max_label_len, \"---------------\", \"------\", \"------\", \"------\", \"------\", \"------\", \"------\", \"------\" );\r\n", +"\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" fprintf( stdout, dfmt, max_label_len, wmops[i].label, update_cnt == 0 ? 0 : (float) wmops[i].call_number / update_cnt,\r\n", +" wmops[i].min_selfcnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_selfcnt,\r\n", +" FAC * wmops[i].max_selfcnt,\r\n", +" wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_selfcnt / wmops[i].update_cnt,\r\n", +" wmops[i].min_cnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_cnt,\r\n", +" FAC * wmops[i].max_cnt,\r\n", +" wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_cnt / wmops[i].update_cnt );\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, sfmts, max_label_len, \"---------------\", \"------\", \"------\", \"------\", \"------\" );\r\n", +" fprintf( stdout, dfmts, max_label_len, \"total\", (float) update_cnt, update_cnt == 0 ? 0 : FAC * min_cnt, FAC * max_cnt, update_cnt == 0 ? 0 : FAC * ops_cnt / update_cnt );\r\n", +" fprintf( stdout, \"\\n\" );\r\n", +"\r\n", +"#ifdef WMOPS_WC_FRAME_ANALYSIS\r\n", +" fprintf( stdout, \"\\nComplexity analysis for the worst-case frame %ld:\\n\\n\", fnum_cnt_wc );\r\n", +" fprintf( stdout, \"%*s %8s %10s %12s\\n\", max_label_len, \" routine\", \" calls\", \" SELF\", \" CUMULATIVE\" );\r\n", +" fprintf( stdout, \"%*s %8s %10s %10s\\n\", max_label_len, \"---------------\", \"------\", \"------\", \"----------\" );\r\n", +"\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" if ( wmops[i].wc_call_number > 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"%*s %8d %10.3f %12.3f\\n\", max_label_len, wmops[i].label, wmops[i].wc_call_number, FAC * wmops[i].wc_selfcnt, FAC * wmops[i].wc_cnt );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, \"\\nCall tree for the worst-case frame %ld:\\n\\n\", fnum_cnt_wc );\r\n", +" fprintf( stdout, sfmtt, \" function\", \"num\", \"called by \" );\r\n", +" fprintf( stdout, sfmtt, \"---------------\", \"---\", \"--------------\" );\r\n", +"\r\n", +" for ( i = 0; i < num_wmops_records; i++ )\r\n", +" {\r\n", +" if ( wmops[i].wc_call_number > 0 )\r\n", +" {\r\n", +" fprintf( stdout, dfmtt, wmops[i].label, i );\r\n", +" for ( j = 0; wmops[i].call_tree[j] != -1 && j < MAX_CALL_TREE_DEPTH; j++ )\r\n", +" {\r\n", +" if ( j != 0 )\r\n", +" {\r\n", +" fprintf( stdout, \", \" );\r\n", +" }\r\n", +" fprintf( stdout, \"%d\", wmops[i].call_tree[j] );\r\n", +" }\r\n", +" fprintf( stdout, \"\\n\" );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, \"\\n\\n\" );\r\n", +"\r\n", +" fprintf( stdout, \"\\nInstruction type analysis for the worst-case frame %ld:\\n\\n\", fnum_cnt_wc ); \r\n", +" for ( i = 0; i < NUM_INST; i++ )\r\n", +" {\r\n", +" switch ( (enum instructions) i )\r\n", +" {\r\n", +" case _ADD:\r\n", +" fprintf( stdout, \"\\tAdds: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _ABS:\r\n", +" fprintf( stdout, \"\\tAbsolutes: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _MULT:\r\n", +" fprintf( stdout, \"\\tMultiplies: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _MAC:\r\n", +" fprintf( stdout, \"\\tMACs: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _MOVE:\r\n", +" fprintf( stdout, \"\\tMoves: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _STORE:\r\n", +" fprintf( stdout, \"\\tStores: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _LOGIC:\r\n", +" fprintf( stdout, \"\\tLogicals: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _SHIFT:\r\n", +" fprintf( stdout, \"\\tShifts: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _BRANCH:\r\n", +" fprintf( stdout, \"\\tBranches: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _DIV:\r\n", +" fprintf( stdout, \"\\tDivisions: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _SQRT:\r\n", +" fprintf( stdout, \"\\tSquare Root: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _TRANS:\r\n", +" fprintf( stdout, \"\\tTrans: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _FUNC:\r\n", +" fprintf( stdout, \"\\tFunc Call: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _LOOP:\r\n", +" fprintf( stdout, \"\\tLoop Init: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _INDIRECT:\r\n", +" fprintf( stdout, \"\\tIndirect Addr: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _PTR_INIT:\r\n", +" fprintf( stdout, \"\\tPointer Init: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _TEST:\r\n", +" fprintf( stdout, \"\\tExtra condit.: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _POWER:\r\n", +" fprintf( stdout, \"\\tExponential: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _LOG:\r\n", +" fprintf( stdout, \"\\tLogarithm: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" case _MISC:\r\n", +" fprintf( stdout, \"\\tAll other op.: %12.1f\\n\", inst_cnt_wc[i] );\r\n", +" break;\r\n", +" default:\r\n", +" fprintf( stdout, \"\\tERROR: Invalid instruction type: %d\\n\\n\", i );\r\n", +" }\r\n", +" }\r\n", +"#endif\r\n", +"\r\n", +" /* De-allocate the list of wmops record */\r\n", +" if ( wmops != NULL )\r\n", +" {\r\n", +" free( wmops );\r\n", +" }\r\n", +"\r\n", +" /* De-allocate the list of wmops caller functions */\r\n", +" if ( wmops_caller_stack != NULL )\r\n", +" {\r\n", +" free( wmops_caller_stack );\r\n", +" }\r\n", +"\r\n", +" /* De-allocate the BASOP WMOPS counter */\r\n", +" if ( multiCounter != NULL )\r\n", +" {\r\n", +" free( multiCounter );\r\n", +" }\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * Memory counting tool measuring RAM usage (stack and heap)\r\n", +" *\r\n", +" * Maximum RAM is measured by monitoring the total allocated memory (stack and heap) in each frame.\r\n", +" *\r\n", +" * Maximum stack is measured by monitoring the difference between the 'top' and 'bottom' of the stack. The 'bottom' of the stack is updated in each function\r\n", +" * with a macro 'func_start_' which is inserted automatically to all functions during the instrumentation process.\r\n", +" *\r\n", +" * Maximum heap is measured by summing the sizes of all memory blocks allocated by malloc() or calloc() and deallocated by free(). The maximum heap size is\r\n", +" * updated each time when the macros malloc_() or calloc_() is invoked. The macros 'malloc_ and calloc_' are inserted automatically during the instrumentation process.\r\n", +" * As part of heap measurements, intra-frame heap and inter-frame heap are measured separately. Intra-frame heap refers to heap memory which is allocated and deallocated\r\n", +" * within a single frame. Inter-frame heap, on the contrary, refers to heap memory which is reserved for more than one frame.\r\n", +" *\r\n", +" * In order to run the memory counting tool the function reset_mem(cnt_size) must be called at the beginning of the encoding/decoding process.\r\n", +" * The unit in which memory consumption is reported is set via the parameter 'cnt_size'. It can be set to 0 (bytes), 1 (32b words) or 2 (64b words).\r\n", +" * At the end of the encoding/decoding process, 'print_mem()' function may be called to print basic information about memory consumption. If the macro 'MEM_COUNT_DETAILS'\r\n", +" * is activated, detailed information is printed\r\n", +" *\r\n", +" * The macro 'WMOPS' needs to be activated to enable memory counting. To avoid the instrumentation of malloc()/calloc()/free() calls, use\r\n", +" * #define WMC_TOOL_SKIP ... #undef WMC_TOOL_SKIP macro pair around the malloc(), calloc() and free().\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"/* This is the value (in bytes) towards which the block size is rounded. For example, a block of 123 bytes, when using\r\n", +" a 32 bits system, will end up taking 124 bytes since the last unused byte cannot be used for another block. */\r\n", +"#ifdef MEM_ALIGN_64BITS\r\n", +"#define BLOCK_ROUNDING 8 /* Align on 64 Bits */\r\n", +"#else\r\n", +"#define BLOCK_ROUNDING 4 /* Align on 32 Bits */\r\n", +"#endif\r\n", +"\r\n", +"#define N_32BITS_BLOCKS ( BLOCK_ROUNDING / sizeof( int32_t ) )\r\n", +"#define ROUND_BLOCK_SIZE( n ) ( ( ( n ) + BLOCK_ROUNDING - 1 ) & ~( BLOCK_ROUNDING - 1 ) )\r\n", +"\r\n", +"#define MAGIC_VALUE_OOB 0x12A534F0 /* Signature value which is inserted before and after each allocated memory block, used to detect out-of-bound access */\r\n", +"#define MAGIC_VALUE_USED ( ~MAGIC_VALUE_OOB ) /* Value used to pre-fill allocated memory blocks, used to calculate actual memory usage */\r\n", +"#define OOB_START 0x1 /* Flag indicating out-of-bounds access before memory block */\r\n", +"#define OOB_END 0x2 /* Flag indicating out-of-bounds access after memory block */\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +"const char *csv_filename = \"mem_analysis.csv\";\r\n", +"static FILE *fid_csv_filename = NULL;\r\n", +"#endif\r\n", +"\r\n", +"typedef struct\r\n", +"{\r\n", +" char function_name[MAX_FUNCTION_NAME_LENGTH + 1];\r\n", +" int16_t *stack_ptr;\r\n", +"} caller_info;\r\n", +"\r\n", +"static caller_info *stack_callers[2] = {NULL, NULL};\r\n", +"\r\n", +"static int16_t *ptr_base_stack = 0; /* Pointer to the bottom of stack (base pointer). Stack grows up. */\r\n", +"static int16_t *ptr_current_stack = 0; /* Pointer to the current stack pointer */\r\n", +"static int16_t *ptr_max_stack = 0; /* Pointer to the maximum stack pointer (the farest point from the bottom of stack) */\r\n", +"static int32_t wc_stack_frame = 0; /* Frame corresponding to the worst-case stack usage */\r\n", +"static int current_calls = 0, max_num_calls = MAX_NUM_RECORDS;\r\n", +"static char location_max_stack[256] = \"undefined\";\r\n", +"\r\n", +"/* Heap-related variables */\r\n", +"typedef struct\r\n", +"{\r\n", +" char name[MAX_FUNCTION_NAME_LENGTH + 1]; /* +1 for NUL */\r\n", +" char params[1 + MAX_PARAMS_LENGTH + 1]; /* +1 for 'm'/'c' alloc & +1 for NUL */\r\n", +" unsigned long hash;\r\n", +" int lineno;\r\n", +" void *block_ptr;\r\n", +" int block_size;\r\n", +" unsigned long total_block_size; /* Cumulative sum of the allocated size in the session */\r\n", +" unsigned long total_used_size; /* Cumulative sum of the used size in the session */\r\n", +" int wc_heap_size_intra_frame; /* Worst-Case Intra-Frame Heap Size */\r\n", +" int wc_heap_size_inter_frame; /* Worst-Case Inter-Frame Heap Size */\r\n", +" int frame_allocated; /* Frame number in which the Memory Block has been allocated (-1 if not allocated at the moment) */\r\n", +" int OOB_Flag;\r\n", +" int noccurances; /* Number of times that the memory block has been allocated in a frame */\r\n", +"} allocator_record;\r\n", +"\r\n", +"allocator_record *allocation_list = NULL;\r\n", +"\r\n", +"static int Num_Records, Max_Num_Records;\r\n", +"static size_t Stat_Cnt_Size = USE_BYTES;\r\n", +"static const char *Count_Unit[] = { \"bytes\", \"words\", \"words\", \"words\" };\r\n", +"\r\n", +"static int32_t wc_ram_size, wc_ram_frame;\r\n", +"static int32_t current_heap_size;\r\n", +"static int *list_wc_intra_frame_heap, n_items_wc_intra_frame_heap, max_items_wc_intra_frame_heap, size_wc_intra_frame_heap, location_wc_intra_frame_heap;\r\n", +"static int *list_current_inter_frame_heap, n_items_current_inter_frame_heap, max_items_current_inter_frame_heap, size_current_inter_frame_heap;\r\n", +"static int *list_wc_inter_frame_heap, n_items_wc_inter_frame_heap, max_items_wc_inter_frame_heap, size_wc_inter_frame_heap, location_wc_inter_frame_heap;\r\n", +"\r\n", +"/* Local Functions */\r\n", +"static unsigned long malloc_hash( const char *func_name, int func_lineno, char *size_str );\r\n", +"allocator_record *get_mem_record( unsigned long *hash, const char *func_name, int func_lineno, char *size_str, int *index_record );\r\n", +"static void *mem_alloc_block( size_t size, const char *size_str );\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * reset_mem()\r\n", +" *\r\n", +" * Initialize/reset memory counting tool (stack and heap)\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"void reset_mem( Counting_Size cnt_size )\r\n", +"{\r\n", +" int16_t something;\r\n", +" size_t tmp_size;\r\n", +"\r\n", +" /* initialize list of stack records */\r\n", +" if ( stack_callers[0] == NULL )\r\n", +" {\r\n", +" stack_callers[0] = malloc( MAX_NUM_RECORDS * sizeof( caller_info ) );\r\n", +" stack_callers[1] = malloc( MAX_NUM_RECORDS * sizeof( caller_info ) );\r\n", +" }\r\n", +"\r\n", +" if ( stack_callers[0] == NULL || stack_callers[1] == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Unable to Allocate List of Stack Records!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" current_calls = 0;\r\n", +" max_num_calls = MAX_NUM_RECORDS;\r\n", +"\r\n", +" /* initialize stack pointers */\r\n", +" ptr_base_stack = &something;\r\n", +" ptr_max_stack = ptr_base_stack;\r\n", +" ptr_current_stack = ptr_base_stack;\r\n", +"\r\n", +" /* initialize the unit of memory block size */\r\n", +" Stat_Cnt_Size = cnt_size;\r\n", +"\r\n", +" /* Check, if sizeof(int32_t) is 4 bytes */\r\n", +" tmp_size = sizeof( int32_t );\r\n", +" if ( tmp_size != 4 )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Expecting 'int32_t' to be a 32 Bits Integer!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* create allocation list for malloc() memory blocks */\r\n", +" if ( allocation_list == NULL )\r\n", +" {\r\n", +" allocation_list = malloc( MAX_NUM_RECORDS * sizeof( allocator_record ) );\r\n", +" }\r\n", +"\r\n", +" if ( allocation_list == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Unable to Create List of Memory Blocks!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" Num_Records = 0;\r\n", +" Max_Num_Records = MAX_NUM_RECORDS;\r\n", +"\r\n", +" wc_ram_size = 0;\r\n", +" wc_ram_frame = -1;\r\n", +" current_heap_size = 0;\r\n", +"\r\n", +" /* heap allocation tree */\r\n", +" heap_allocation_call_tree_max_size = MAX_NUM_RECORDS;\r\n", +" if ( heap_allocation_call_tree == NULL )\r\n", +" {\r\n", +" heap_allocation_call_tree = (int *) malloc( heap_allocation_call_tree_max_size * sizeof( int ) );\r\n", +" memset( heap_allocation_call_tree, -1, heap_allocation_call_tree_max_size * sizeof( int ) );\r\n", +" }\r\n", +" heap_allocation_call_tree_size = 0;\r\n", +"\r\n", +" /* wc intra-frame heap */\r\n", +" max_items_wc_intra_frame_heap = MAX_NUM_RECORDS;\r\n", +" if ( list_wc_intra_frame_heap == NULL )\r\n", +" {\r\n", +" list_wc_intra_frame_heap = (int *) malloc( max_items_wc_intra_frame_heap * sizeof( int ) );\r\n", +" memset( list_wc_intra_frame_heap, -1, max_items_wc_intra_frame_heap * sizeof( int ) );\r\n", +" }\r\n", +" n_items_wc_intra_frame_heap = 0;\r\n", +" size_wc_intra_frame_heap = 0;\r\n", +" location_wc_intra_frame_heap = -1;\r\n", +"\r\n", +" /* current inter-frame heap */\r\n", +" max_items_current_inter_frame_heap = MAX_NUM_RECORDS;\r\n", +" if ( list_current_inter_frame_heap == NULL )\r\n", +" {\r\n", +" list_current_inter_frame_heap = (int *) malloc( max_items_current_inter_frame_heap * sizeof( int ) );\r\n", +" memset( list_current_inter_frame_heap, -1, max_items_current_inter_frame_heap * sizeof( int ) );\r\n", +" }\r\n", +" n_items_current_inter_frame_heap = 0;\r\n", +" size_current_inter_frame_heap = 0;\r\n", +"\r\n", +" /* wc inter-frame heap */\r\n", +" max_items_wc_inter_frame_heap = MAX_NUM_RECORDS;\r\n", +" if ( list_wc_inter_frame_heap == NULL )\r\n", +" {\r\n", +" list_wc_inter_frame_heap = (int *) malloc( max_items_wc_inter_frame_heap * sizeof( int ) );\r\n", +" memset( list_wc_inter_frame_heap, -1, max_items_wc_inter_frame_heap * sizeof( int ) );\r\n", +" }\r\n", +" n_items_wc_inter_frame_heap = 0;\r\n", +" size_wc_inter_frame_heap = 0;\r\n", +" location_wc_inter_frame_heap = -1;\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +" /* Check, if the .csv file has already been opened */\r\n", +" if ( fid_csv_filename == NULL )\r\n", +" {\r\n", +" fid_csv_filename = fopen( csv_filename, \"wb\" );\r\n", +"\r\n", +" if ( fid_csv_filename == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"\\nCannot open %s!\\n\\n\", csv_filename );\r\n", +" exit( -1 );\r\n", +" }\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" /* reset file */\r\n", +" rewind( fid_csv_filename );\r\n", +" }\r\n", +"#endif\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * reset_stack()\r\n", +" *\r\n", +" * Reset stack pointer\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"void reset_stack( void )\r\n", +"{\r\n", +" int16_t something;\r\n", +"\r\n", +" /* initialize/reset stack pointers */\r\n", +" ptr_base_stack = &something;\r\n", +" ptr_max_stack = ptr_base_stack;\r\n", +" ptr_current_stack = ptr_base_stack;\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * push_stack()\r\n", +" *\r\n", +" * Check the current stack pointer and update the maximum stack pointer, if new maximum found.\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"int push_stack( const char *filename, const char *fctname )\r\n", +"{\r\n", +" int16_t something;\r\n", +" int32_t current_stack_size;\r\n", +"\r\n", +" ptr_current_stack = &something;\r\n", +"\r\n", +" (void) *filename; /* to avoid compilation warning */\r\n", +"\r\n", +" if ( current_calls >= max_num_calls )\r\n", +" {\r\n", +" /* There is no room for a new record -> reallocate the list */\r\n", +" max_num_calls += MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" stack_callers[0] = realloc( stack_callers[0], max_num_calls * sizeof( caller_info ) );\r\n", +" stack_callers[1] = realloc( stack_callers[1], max_num_calls * sizeof( caller_info ) );\r\n", +" }\r\n", +"\r\n", +" /* Valid Function Name? */\r\n", +" if ( fctname[0] == 0 )\r\n", +" { /* No */\r\n", +" fprintf( stderr, \"Invalid function name for call stack info.\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* Save the Name of the Calling Function in the Table */\r\n", +" strncpy( stack_callers[0][current_calls].function_name, fctname, MAX_FUNCTION_NAME_LENGTH );\r\n", +" stack_callers[0][current_calls].function_name[MAX_FUNCTION_NAME_LENGTH] = 0; /* Nul Terminate */\r\n", +"\r\n", +" /* Save the Stack Pointer */\r\n", +" stack_callers[0][current_calls].stack_ptr = ptr_current_stack;\r\n", +"\r\n", +" /* Increase the Number of Calls in the List */\r\n", +" current_calls++;\r\n", +"\r\n", +" /* Is this the First Time or the Worst Case? */\r\n", +" if ( ptr_current_stack < ptr_max_stack || ptr_max_stack == NULL )\r\n", +" { /* Yes */\r\n", +" /* Save Info about it */\r\n", +" ptr_max_stack = ptr_current_stack;\r\n", +"\r\n", +" /* save the worst-case frame number */\r\n", +" /* current frame number is stored in the variable update_cnt and updated in the function update_wmops() */\r\n", +" wc_stack_frame = update_cnt; \r\n", +" strncpy( location_max_stack, fctname, sizeof( location_max_stack ) - 1 );\r\n", +" location_max_stack[sizeof( location_max_stack ) - 1] = '\\0';\r\n", +"\r\n", +" /* Save Call Tree */\r\n", +" memmove( stack_callers[1], stack_callers[0], sizeof( caller_info ) * current_calls );\r\n", +"\r\n", +" /* Terminate the List with 0 (for printing purposes) */\r\n", +" if ( current_calls < max_num_calls )\r\n", +" {\r\n", +" stack_callers[1][current_calls].function_name[0] = 0;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Check, if This is the New Worst-Case RAM (stack + heap) */\r\n", +" current_stack_size = (int32_t) ( ( ( ptr_base_stack - ptr_current_stack ) * sizeof( int16_t ) ) );\r\n", +"\r\n", +" if ( current_stack_size < 0 )\r\n", +" {\r\n", +" /* prevent negative stack size */\r\n", +" current_stack_size = 0;\r\n", +" }\r\n", +"\r\n", +" if ( current_stack_size + current_heap_size > wc_ram_size )\r\n", +" {\r\n", +" wc_ram_size = current_stack_size + current_heap_size;\r\n", +" wc_ram_frame = update_cnt;\r\n", +" }\r\n", +"\r\n", +" return 0 /* for Now */;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * pop_stack()\r\n", +" *\r\n", +" * Remove stack caller entry from the list\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"int pop_stack( const char *filename, const char *fctname )\r\n", +"{\r\n", +" caller_info *caller_info_ptr;\r\n", +"\r\n", +" (void) *filename; /* to avoid compilation warning */\r\n", +"\r\n", +" /* Decrease the Number of Records */\r\n", +" current_calls--;\r\n", +"\r\n", +" /* Get Pointer to Caller Information */\r\n", +" caller_info_ptr = &stack_callers[0][current_calls];\r\n", +"\r\n", +" /* Check, if the Function Names Match */\r\n", +" if ( strncmp( caller_info_ptr->function_name, fctname, MAX_FUNCTION_NAME_LENGTH ) != 0 )\r\n", +" {\r\n", +" fprintf( stderr, \"Invalid usage of pop_stack()\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* Erase Entry */\r\n", +" caller_info_ptr->function_name[0] = 0;\r\n", +"\r\n", +" /* Retrieve previous stack pointer */\r\n", +" if ( current_calls == 0 )\r\n", +" {\r\n", +" ptr_current_stack = ptr_base_stack;\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" ptr_current_stack = stack_callers[0][current_calls - 1].stack_ptr;\r\n", +" }\r\n", +"\r\n", +" return 0 /* for Now */;\r\n", +"}\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * print_stack_call_tree()\r\n", +" *\r\n", +" * Print detailed information about worst-case stack usage\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static void print_stack_call_tree( void )\r\n", +"{\r\n", +" caller_info *caller_info_ptr;\r\n", +" int call_level;\r\n", +" char fctname[MAX_FUNCTION_NAME_LENGTH + 1];\r\n", +"\r\n", +" fprintf( stdout, \"\\nList of functions when maximum stack size is reached:\\n\\n\" );\r\n", +"\r\n", +" caller_info_ptr = &stack_callers[1][0];\r\n", +" for ( call_level = 0; call_level < max_num_calls; call_level++ )\r\n", +" {\r\n", +" /* Done? */\r\n", +" if ( caller_info_ptr->function_name[0] == 0 )\r\n", +" {\r\n", +" break;\r\n", +" }\r\n", +"\r\n", +" /* Print Name */\r\n", +" strncpy( fctname, caller_info_ptr->function_name, MAX_FUNCTION_NAME_LENGTH );\r\n", +" strcat( fctname, \"()\" );\r\n", +" fprintf( stdout, \"%-42s\", fctname );\r\n", +"\r\n", +" /* Print Stack Usage (Based on Difference) */\r\n", +" if ( call_level != 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"%lu %s\\n\", ( ( ( caller_info_ptr - 1 )->stack_ptr - caller_info_ptr->stack_ptr ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" fprintf( stdout, \"%lu %s\\n\", ( ( ptr_base_stack - caller_info_ptr->stack_ptr ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +"\r\n", +" /* Advance */\r\n", +" caller_info_ptr++;\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, \"\\n\" );\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"#endif\r\n", +"\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * mem_alloc()\r\n", +" *\r\n", +" * Creates new record, stores auxiliary information about which function allocated the memory, line number, parameters, etc.\r\n", +" * Finally, it allocates physical memory using malloc()\r\n", +" * The function also updates worst-case heap size and worst-case RAM size\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"void *mem_alloc(\r\n", +" const char *func_name,\r\n", +" int func_lineno,\r\n", +" size_t size,\r\n", +" char *size_str /* the first char indicates m-alloc or c-alloc */ )\r\n", +"{\r\n", +" int index_record;\r\n", +" int32_t current_stack_size;\r\n", +" unsigned long hash;\r\n", +" allocator_record *ptr_record;\r\n", +"\r\n", +" if ( size == 0 )\r\n", +" {\r\n", +" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Size of Zero not Supported\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* Search for an existing record (that has been de-allocated before) */\r\n", +" index_record = 0;\r\n", +" while ( ( ptr_record = get_mem_record( &hash, func_name, func_lineno, size_str, &index_record ) ) != NULL )\r\n", +" {\r\n", +" if ( ptr_record->frame_allocated == -1 )\r\n", +" {\r\n", +" break;\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" index_record++;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Create new record */\r\n", +" if ( ptr_record == NULL )\r\n", +" {\r\n", +" if ( Num_Records >= Max_Num_Records )\r\n", +" {\r\n", +" /* There is no room for a new record -> reallocate memory */\r\n", +" Max_Num_Records += MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" allocation_list = realloc( allocation_list, Max_Num_Records * sizeof( allocator_record ) );\r\n", +" }\r\n", +"\r\n", +" ptr_record = &( allocation_list[Num_Records] );\r\n", +"\r\n", +" /* Initialize new record */\r\n", +" ptr_record->hash = hash;\r\n", +" ptr_record->noccurances = 0;\r\n", +" ptr_record->total_block_size = 0;\r\n", +" ptr_record->total_used_size = 0;\r\n", +" ptr_record->frame_allocated = -1;\r\n", +" ptr_record->OOB_Flag = 0;\r\n", +" ptr_record->wc_heap_size_intra_frame = -1;\r\n", +" ptr_record->wc_heap_size_inter_frame = -1;\r\n", +"\r\n", +" index_record = Num_Records;\r\n", +" Num_Records++;\r\n", +" }\r\n", +"\r\n", +" /* Allocate memory block for the new record, add signature before the beginning and after the memory block and fill it with magic value */\r\n", +" ptr_record->block_ptr = mem_alloc_block( size, size_str );\r\n", +"\r\n", +" if ( ptr_record->block_ptr == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Error: Cannot Allocate Memory!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* Save all auxiliary information about the memory block */\r\n", +" strncpy( ptr_record->name, func_name, MAX_FUNCTION_NAME_LENGTH );\r\n", +" ptr_record->name[MAX_FUNCTION_NAME_LENGTH] = '\\0';\r\n", +" strncpy( ptr_record->params, size_str, MAX_PARAMS_LENGTH ); /* Note: The size string starts with either 'm' or 'c' to indicate 'm'alloc or 'c'alloc */\r\n", +" ptr_record->params[MAX_PARAMS_LENGTH] = '\\0';\r\n", +" ptr_record->lineno = func_lineno;\r\n", +" ptr_record->block_size = size;\r\n", +" ptr_record->total_block_size += size;\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +" /* Export heap memory allocation record to the .csv file */\r\n", +" fprintf( fid_csv_filename, \"A,%d,%s,%d,%d\\n\", update_cnt, ptr_record->name, ptr_record->lineno, ptr_record->block_size );\r\n", +"#endif\r\n", +"\r\n", +" if ( ptr_record->frame_allocated != -1 )\r\n", +" {\r\n", +" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Error: Attempt to Allocate the Same Memory Block with Freeing it First!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" ptr_record->frame_allocated = update_cnt; /* Store the current frame number -> later it will be used to determine the total duration */\r\n", +"\r\n", +" /* Update Heap Size in the current frame */\r\n", +" current_heap_size += ptr_record->block_size;\r\n", +"\r\n", +" /* Check, if this is the new Worst-Case RAM (stack + heap) */\r\n", +" current_stack_size = (int32_t) ( ( ( ptr_base_stack - ptr_current_stack ) * sizeof( int16_t ) ) );\r\n", +" if ( current_stack_size + current_heap_size > wc_ram_size )\r\n", +" {\r\n", +" wc_ram_size = current_stack_size + current_heap_size;\r\n", +" wc_ram_frame = update_cnt;\r\n", +" }\r\n", +"\r\n", +" /* Add new entry to the heap allocation call tree */\r\n", +" if ( heap_allocation_call_tree == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Heap allocation call tree not created!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* check, if the maximum size of the call tree has been reached -> resize if so */\r\n", +" if ( heap_allocation_call_tree_size >= heap_allocation_call_tree_max_size )\r\n", +" {\r\n", +" heap_allocation_call_tree_max_size += MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" heap_allocation_call_tree = (int *) realloc( heap_allocation_call_tree, heap_allocation_call_tree_max_size * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" /* push new entry (positive number means push op, neagtive number means pop op; zero index must be converted to 0.01 :-) */\r\n", +" heap_allocation_call_tree[heap_allocation_call_tree_size++] = index_record;\r\n", +"\r\n", +" return ptr_record->block_ptr;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * mem_alloc_block()\r\n", +" *\r\n", +" * Physical allocation of memory using malloc(). Appends 'signature' before and after the block,\r\n", +" * pre-fills memory block with magic value\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static void *mem_alloc_block( size_t size, const char *size_str )\r\n", +"{\r\n", +" size_t rounded_size;\r\n", +" void *block_ptr;\r\n", +" char *tmp_ptr;\r\n", +" size_t n, f;\r\n", +" int32_t fill_value;\r\n", +" int32_t *ptr32;\r\n", +" int32_t mask, temp;\r\n", +"\r\n", +" /* Round Up Block Size */\r\n", +" rounded_size = ROUND_BLOCK_SIZE( size );\r\n", +"\r\n", +" /* Allocate memory using the standard malloc() by adding room for Signature Values */\r\n", +" block_ptr = malloc( rounded_size + BLOCK_ROUNDING * 2 );\r\n", +"\r\n", +" if ( block_ptr == NULL )\r\n", +" {\r\n", +" return NULL;\r\n", +" }\r\n", +"\r\n", +" /* Add Signature Before the Start of the Block */\r\n", +" ptr32 = (int32_t *) block_ptr;\r\n", +" n = N_32BITS_BLOCKS;\r\n", +" do\r\n", +" {\r\n", +" *ptr32++ = MAGIC_VALUE_OOB;\r\n", +" } while ( --n );\r\n", +"\r\n", +" /* Fill Memory Block with Magic Value or 0 */\r\n", +" fill_value = MAGIC_VALUE_USED;\r\n", +" if ( size_str[0] == 'c' )\r\n", +" {\r\n", +" fill_value = 0x00000000;\r\n", +" }\r\n", +" n = size / sizeof( int32_t );\r\n", +" while ( n-- )\r\n", +" {\r\n", +" *ptr32++ = fill_value;\r\n", +" }\r\n", +"\r\n", +" /* Fill the Reminder of the Memory Block - After Rounding */\r\n", +" n = rounded_size - size;\r\n", +" f = n % sizeof( int32_t );\r\n", +" if ( f != 0 )\r\n", +" {\r\n", +" /* when filling with '0' need to adapt the magic value */\r\n", +" /* shift by [1->24, 2->16, 3->8] */\r\n", +" mask = 0xFFFFFFFF << ( ( sizeof( int32_t ) - f ) * 8 ); /* (1) */\r\n", +" temp = MAGIC_VALUE_OOB & mask;\r\n", +" if ( fill_value != 0x0 )\r\n", +" { /* for malloc merge fill value */\r\n", +" temp += ( ~mask ) & MAGIC_VALUE_USED;\r\n", +" } /* for calloc the code in (1) above already introduces zeros */\r\n", +" *ptr32++ = temp;\r\n", +" }\r\n", +" n /= sizeof( int32_t );\r\n", +" n += N_32BITS_BLOCKS;\r\n", +"\r\n", +" /* Add Signature After the End of Block */\r\n", +" do\r\n", +" {\r\n", +" *ptr32++ = MAGIC_VALUE_OOB;\r\n", +" } while ( --n );\r\n", +"\r\n", +" /* Adjust the Memory Block Pointer (Magic Value Before and After the Memory Block Requested) */\r\n", +" tmp_ptr = (char *) block_ptr;\r\n", +" tmp_ptr += BLOCK_ROUNDING;\r\n", +" block_ptr = (void *) tmp_ptr;\r\n", +"\r\n", +" return block_ptr;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * mem_set_usage()\r\n", +" *\r\n", +" * Calculates actual usage of memory block by checking the magic value that was used to pre-fill\r\n", +" * each memory block during its allocation\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static int mem_set_usage( allocator_record *record_ptr )\r\n", +"{\r\n", +" int total_bytes_used;\r\n", +"\r\n", +" size_t n;\r\n", +" int32_t *ptr32;\r\n", +" char *ptr8;\r\n", +" size_t total_bytes;\r\n", +" int32_t fill_value;\r\n", +"\r\n", +" fill_value = MAGIC_VALUE_USED;\r\n", +" if ( ( record_ptr->params[0] ) == 'c' )\r\n", +" {\r\n", +" fill_value = 0x00000000;\r\n", +" }\r\n", +"\r\n", +" total_bytes = record_ptr->block_size;\r\n", +"\r\n", +" /* Check 4 bytes at a time */\r\n", +" ptr32 = (int32_t *) record_ptr->block_ptr;\r\n", +" total_bytes_used = 0;\r\n", +" for ( n = total_bytes / sizeof( int32_t ); n > 0; n-- )\r\n", +" {\r\n", +" if ( *ptr32++ != fill_value )\r\n", +" {\r\n", +" total_bytes_used += sizeof( int32_t );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Check remaining bytes (If Applicable) 1 byte at a time */\r\n", +" ptr8 = (char *) ptr32;\r\n", +" for ( n = total_bytes % sizeof( int32_t ); n > 0; n-- )\r\n", +" {\r\n", +" if ( *ptr8++ != (char) fill_value )\r\n", +" {\r\n", +" total_bytes_used++;\r\n", +" }\r\n", +"\r\n", +" /* Update Value */\r\n", +" fill_value >>= 8;\r\n", +" }\r\n", +"\r\n", +" return total_bytes_used;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * mem_check_OOB()\r\n", +" *\r\n", +" * Checks, if out-of-bounds access has occured. This is done by inspecting the 'signature' value\r\n", +" * taht has been added before and after the memory block during its allocation\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static unsigned int mem_check_OOB( allocator_record *record_ptr )\r\n", +"{\r\n", +" int32_t *ptr32;\r\n", +" unsigned int OOB_Flag = 0x0;\r\n", +" int32_t mask;\r\n", +" size_t i;\r\n", +" int f;\r\n", +"\r\n", +" ptr32 = (int32_t *) record_ptr->block_ptr - N_32BITS_BLOCKS;\r\n", +"\r\n", +" /* Check the Signature at the Beginning of Memory Block */\r\n", +" i = N_32BITS_BLOCKS;\r\n", +" do\r\n", +" {\r\n", +" if ( *ptr32++ ^ MAGIC_VALUE_OOB )\r\n", +" {\r\n", +" OOB_Flag |= OOB_START;\r\n", +" }\r\n", +" } while ( --i );\r\n", +"\r\n", +" /* Advance to End (Snap to lowest 32 Bits) */\r\n", +" ptr32 += record_ptr->block_size / sizeof( int32_t );\r\n", +"\r\n", +" /* Calculate Unused Space That has been added to get to the rounded Block Size */\r\n", +" i = ROUND_BLOCK_SIZE( record_ptr->block_size ) - record_ptr->block_size;\r\n", +"\r\n", +" /* Partial Check of Signature at the End of Memory Block (for block size that has been rounded) */\r\n", +" f = i % sizeof( int32_t );\r\n", +" if ( f != 0 )\r\n", +" {\r\n", +" mask = 0xFFFFFFFF << ( ( sizeof( int32_t ) - f ) * 8 );\r\n", +" if ( ( *ptr32++ ^ MAGIC_VALUE_OOB ) & mask )\r\n", +" {\r\n", +" OOB_Flag |= OOB_END;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Full Check of Signature at the End of Memory Block, i.e. all 32 Bits (for the remainder after rounding) */\r\n", +" i /= sizeof( int32_t );\r\n", +" i += N_32BITS_BLOCKS;\r\n", +" do\r\n", +" {\r\n", +" if ( *ptr32++ ^ MAGIC_VALUE_OOB )\r\n", +" {\r\n", +" OOB_Flag |= OOB_END;\r\n", +" }\r\n", +" } while ( --i );\r\n", +"\r\n", +" return OOB_Flag;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * malloc_hash()\r\n", +" *\r\n", +" * Calculate hash from function name, line number and malloc size\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static unsigned long malloc_hash( const char *func_name, int func_lineno, char *size_str )\r\n", +"{\r\n", +" unsigned long hash = 5381;\r\n", +" const char *ptr_str;\r\n", +"\r\n", +" ptr_str = func_name;\r\n", +" while ( ptr_str != NULL && *ptr_str != '\\0' )\r\n", +" {\r\n", +" hash = ( ( hash << 5 ) + hash ) + *ptr_str++; /* hash * 33 + char */\r\n", +" }\r\n", +"\r\n", +" hash = ( ( hash << 5 ) + hash ) + func_lineno; /* hash * 33 + func_lineno */\r\n", +"\r\n", +" ptr_str = size_str;\r\n", +" while ( ptr_str != NULL && *ptr_str != '\\0' )\r\n", +" {\r\n", +" hash = ( ( hash << 5 ) + hash ) + *ptr_str++; /* hash * 33 + char */\r\n", +" }\r\n", +"\r\n", +" return hash;\r\n", +"}\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * get_mem_record()\r\n", +" *\r\n", +" * Search for memory record in the internal list, return NULL if not found\r\n", +" * Start from index_record\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"allocator_record *get_mem_record( unsigned long *hash, const char *func_name, int func_lineno, char *size_str, int *index_record )\r\n", +"{\r\n", +" int i;\r\n", +"\r\n", +" if ( *index_record < 0 || *index_record > Num_Records )\r\n", +" {\r\n", +" return NULL;\r\n", +" }\r\n", +"\r\n", +" /* calculate hash */\r\n", +" *hash = malloc_hash( func_name, func_lineno, size_str );\r\n", +"\r\n", +" for ( i = *index_record; i < Num_Records; i++ )\r\n", +" {\r\n", +" /* check, if memory block is not allocated at the moment and the hash matches */\r\n", +" if ( allocation_list[i].block_ptr == NULL && *hash == allocation_list[i].hash )\r\n", +" {\r\n", +" *index_record = i;\r\n", +" return &( allocation_list[i] );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* not found */\r\n", +" *index_record = -1;\r\n", +" return NULL;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * mem_free()\r\n", +" *\r\n", +" * This function de-allocatesd the memory block and frees the mphysical memory with free().\r\n", +" * It also updates actual and average usage of the memory block.\r\n", +" *\r\n", +" * Note: The record is not removed from the list and may be reused later on in mem_alloc()!\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"void mem_free( const char *func_name, int func_lineno, void *ptr )\r\n", +"{\r\n", +" int i, index_record;\r\n", +" char *tmp_ptr;\r\n", +" allocator_record *ptr_record;\r\n", +"\r\n", +" /* Search for the Block Pointer in the List */\r\n", +" ptr_record = NULL;\r\n", +" index_record = -1;\r\n", +" for ( i = 0; i < Num_Records; i++ )\r\n", +" {\r\n", +" if ( ptr == allocation_list[i].block_ptr )\r\n", +" { /* Yes, Found it */\r\n", +" ptr_record = &( allocation_list[i] );\r\n", +" index_record = i;\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" if ( ptr_record == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", func_name, func_lineno, \"Error: Unable to Find Record Corresponding to the Allocated Memory Block!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* Update the Heap Size */\r\n", +" current_heap_size -= ptr_record->block_size;\r\n", +"\r\n", +" /* Calculate the Actual Usage of the Memory Block (Look for Signature) */\r\n", +" ptr_record->total_used_size += mem_set_usage( ptr_record );\r\n", +"\r\n", +" /* Check, if Out-Of-Bounds Access has been Detected */\r\n", +" ptr_record->OOB_Flag = mem_check_OOB( ptr_record );\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +" /* Export heap memory de-allocation record to the .csv file */\r\n", +" fprintf( fid_csv_filename, \"D,%d,%s,%d,%d\\n\", update_cnt, ptr_record->name, ptr_record->lineno, ptr_record->block_size );\r\n", +"#endif\r\n", +"\r\n", +" /* De-Allocate Memory Block */\r\n", +" tmp_ptr = (char *) ptr;\r\n", +" tmp_ptr -= BLOCK_ROUNDING;\r\n", +" ptr = (void *) tmp_ptr;\r\n", +" free( ptr );\r\n", +"\r\n", +" /* Add new entry to the heap allocation call tree */\r\n", +" if ( heap_allocation_call_tree == NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Error: Heap allocation call tree not created!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +"\r\n", +" /* check, if the maximum size of the call tree has been reached -> resize if so */\r\n", +" if ( heap_allocation_call_tree_size >= heap_allocation_call_tree_max_size )\r\n", +" {\r\n", +" heap_allocation_call_tree_max_size += MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" heap_allocation_call_tree = (int *) realloc( heap_allocation_call_tree, heap_allocation_call_tree_max_size * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" heap_allocation_call_tree[heap_allocation_call_tree_size++] = -index_record;\r\n", +"\r\n", +" /* Reset memory block pointer (this is checked when updating wc intra-frame and inter-frame memory) */\r\n", +" ptr_record->block_ptr = NULL;\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * update_mem()\r\n", +" *\r\n", +" * This function updates the worst-case intra-frame memory and the worst-case inter-frame memory.\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"void update_mem( void )\r\n", +"{\r\n", +" int i, j, flag_alloc = -1, i_record;\r\n", +" int size_current_intra_frame_heap;\r\n", +" int *list_current_intra_frame_heap = NULL, n_items_current_intra_frame_heap;\r\n", +" allocator_record *ptr_record;\r\n", +"\r\n", +" /* process the heap allocation call tree and prepare lists of intra-frame and inter-frame heap memory blocks for this frame */\r\n", +" n_items_current_intra_frame_heap = 0;\r\n", +" size_current_intra_frame_heap = 0;\r\n", +" for ( i = 0; i < heap_allocation_call_tree_size; i++ )\r\n", +" {\r\n", +" /* get the record */\r\n", +" i_record = heap_allocation_call_tree[i];\r\n", +"\r\n", +" if ( i_record > 0 )\r\n", +" {\r\n", +" flag_alloc = 1;\r\n", +" }\r\n", +" else if ( i_record < 0 )\r\n", +" {\r\n", +" flag_alloc = 0;\r\n", +" i_record = -i_record;\r\n", +" }\r\n", +" ptr_record = &( allocation_list[i_record] );\r\n", +"\r\n", +" if ( ptr_record->frame_allocated == update_cnt && ptr_record->block_ptr == NULL )\r\n", +" {\r\n", +" /* intra-frame heap memory */\r\n", +" if ( list_current_intra_frame_heap == NULL )\r\n", +" {\r\n", +" list_current_intra_frame_heap = (int *) malloc( heap_allocation_call_tree_size * sizeof( int ) );\r\n", +" memset( list_current_intra_frame_heap, -1, heap_allocation_call_tree_size * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */\r\n", +" if ( i_record == 0 )\r\n", +" {\r\n", +" flag_alloc = 1;\r\n", +" for ( j = 0; j < n_items_current_intra_frame_heap; j++ )\r\n", +" {\r\n", +" if ( list_current_intra_frame_heap[j] == i_record )\r\n", +" {\r\n", +" flag_alloc = 0;\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" if ( flag_alloc )\r\n", +" {\r\n", +" /* add to list */\r\n", +" list_current_intra_frame_heap[n_items_current_intra_frame_heap++] = i_record;\r\n", +" size_current_intra_frame_heap += ptr_record->block_size;\r\n", +"\r\n", +" /* no need to re-size the list -> the initially allocated size should be large enough */\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" /* remove from list */\r\n", +" for ( j = 0; j < n_items_current_intra_frame_heap; j++ )\r\n", +" {\r\n", +" if ( list_current_intra_frame_heap[j] == i_record )\r\n", +" {\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +" memmove( &list_current_intra_frame_heap[j], &list_current_intra_frame_heap[j + 1], ( n_items_current_intra_frame_heap - j ) * sizeof( int ) );\r\n", +" n_items_current_intra_frame_heap--;\r\n", +" size_current_intra_frame_heap -= ptr_record->block_size;\r\n", +"\r\n", +" /* reset block size */\r\n", +" ptr_record->frame_allocated = -1;\r\n", +" ptr_record->block_size = 0;\r\n", +" }\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" /* inter-frame heap memory */\r\n", +"\r\n", +" /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */\r\n", +" if ( i_record == 0 )\r\n", +" {\r\n", +" flag_alloc = 1;\r\n", +" for ( j = 0; j < n_items_current_inter_frame_heap; j++ )\r\n", +" {\r\n", +" if ( list_current_inter_frame_heap[j] == i_record )\r\n", +" {\r\n", +" flag_alloc = 0;\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" if ( flag_alloc )\r\n", +" {\r\n", +" /* add to list */\r\n", +" if ( n_items_current_inter_frame_heap >= max_items_current_inter_frame_heap )\r\n", +" {\r\n", +" /* resize list, if needed */\r\n", +" max_items_current_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" list_current_inter_frame_heap = realloc( list_current_inter_frame_heap, max_items_current_inter_frame_heap * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" list_current_inter_frame_heap[n_items_current_inter_frame_heap++] = i_record;\r\n", +" size_current_inter_frame_heap += ptr_record->block_size;\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" /* remove from list */\r\n", +" for ( j = 0; j < n_items_current_inter_frame_heap; j++ )\r\n", +" {\r\n", +" if ( list_current_inter_frame_heap[j] == i_record )\r\n", +" {\r\n", +" break;\r\n", +" }\r\n", +" }\r\n", +" memmove( &list_current_inter_frame_heap[j], &list_current_inter_frame_heap[j + 1], ( n_items_current_inter_frame_heap - j ) * sizeof( int ) );\r\n", +" n_items_current_inter_frame_heap--;\r\n", +" size_current_inter_frame_heap -= ptr_record->block_size;\r\n", +"\r\n", +" /* reset block size */\r\n", +" ptr_record->frame_allocated = -1;\r\n", +" ptr_record->block_size = 0;\r\n", +" }\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* check, if this is the new worst-case for intra-frame heap memory */\r\n", +" if ( size_current_intra_frame_heap > size_wc_intra_frame_heap )\r\n", +" {\r\n", +" if ( n_items_current_intra_frame_heap >= max_items_wc_intra_frame_heap )\r\n", +" {\r\n", +" /* resize the list, if needed */\r\n", +" max_items_wc_intra_frame_heap = n_items_current_intra_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" list_wc_intra_frame_heap = realloc( list_wc_intra_frame_heap, max_items_wc_intra_frame_heap * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" /* copy current-frame list to worst-case list */\r\n", +" memmove( list_wc_intra_frame_heap, list_current_intra_frame_heap, n_items_current_intra_frame_heap * sizeof( int ) );\r\n", +" n_items_wc_intra_frame_heap = n_items_current_intra_frame_heap;\r\n", +" size_wc_intra_frame_heap = size_current_intra_frame_heap;\r\n", +" location_wc_intra_frame_heap = update_cnt;\r\n", +"\r\n", +" /* update the wc numbers in all individual records */\r\n", +" for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )\r\n", +" {\r\n", +" i_record = list_wc_intra_frame_heap[i];\r\n", +" ptr_record = &( allocation_list[i_record] );\r\n", +" ptr_record->wc_heap_size_intra_frame = ptr_record->block_size;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* check, if this is the new worst-case for inter-frame heap memory */\r\n", +" if ( size_current_inter_frame_heap > size_wc_inter_frame_heap )\r\n", +" {\r\n", +" if ( n_items_current_inter_frame_heap >= max_items_wc_inter_frame_heap )\r\n", +" {\r\n", +" /* resize list, if needed */\r\n", +" max_items_wc_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;\r\n", +" list_wc_inter_frame_heap = realloc( list_wc_inter_frame_heap, max_items_wc_inter_frame_heap * sizeof( int ) );\r\n", +" }\r\n", +"\r\n", +" /* copy current-frame list to worst-case list */\r\n", +" memmove( list_wc_inter_frame_heap, list_current_inter_frame_heap, n_items_current_inter_frame_heap * sizeof( int ) );\r\n", +" n_items_wc_inter_frame_heap = n_items_current_inter_frame_heap;\r\n", +" size_wc_inter_frame_heap = size_current_inter_frame_heap;\r\n", +" location_wc_inter_frame_heap = update_cnt;\r\n", +"\r\n", +" /* update the wc numbers in all individual records */\r\n", +" for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )\r\n", +" {\r\n", +" i_record = list_wc_inter_frame_heap[i];\r\n", +" ptr_record = &( allocation_list[i_record] );\r\n", +" ptr_record->wc_heap_size_inter_frame = ptr_record->block_size;\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* reset heap allocation call tree */\r\n", +" heap_allocation_call_tree_size = 0;\r\n", +"\r\n", +" /* de-allocate list of intra-frame heap memory blocks in the current fraeme - it's needed only inside this function */\r\n", +" if ( list_current_intra_frame_heap )\r\n", +" {\r\n", +" free( list_current_intra_frame_heap );\r\n", +" }\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * subst()\r\n", +" *\r\n", +" * Substitute character in string\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static void subst( char *s, char from, char to )\r\n", +"{\r\n", +" while ( *s == from )\r\n", +" {\r\n", +" *s++ = to;\r\n", +" }\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * mem_count_summary()\r\n", +" *\r\n", +" * Print detailed (per-item) information about heap memory usage\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"static void mem_count_summary( void )\r\n", +"{\r\n", +" int i, j, index, index_record;\r\n", +" size_t length;\r\n", +" char buf[300], format_str[50], name_str[MAX_FUNCTION_NAME_LENGTH + 3], parms_str[MAX_PARAMS_LENGTH + 1], type_str[10], usage_str[20], size_str[20], line_str[10];\r\n", +" allocator_record *ptr_record, *ptr;\r\n", +"\r\n", +" /* Prepare format string */\r\n", +" sprintf( format_str, \"%%-%ds %%5s %%6s %%-%ds %%20s %%6s \", MAX_FUNCTION_NAME_LENGTH, MAX_PARAMS_LENGTH );\r\n", +"\r\n", +" if ( n_items_wc_intra_frame_heap > 0 )\r\n", +" {\r\n", +" /* Intra-Frame Heap Size */\r\n", +" fprintf( stdout, \"\\nList of memory blocks when maximum intra-frame heap size is reached:\\n\\n\" );\r\n", +"\r\n", +" /* Find duplicate records (same hash and worst-case heap size) */\r\n", +" for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )\r\n", +" {\r\n", +" index_record = list_wc_intra_frame_heap[i];\r\n", +" if ( index_record == -1 )\r\n", +" {\r\n", +" continue;\r\n", +" }\r\n", +"\r\n", +" ptr_record = &( allocation_list[index_record] );\r\n", +" for ( j = i + 1; j < n_items_wc_intra_frame_heap; j++ )\r\n", +" {\r\n", +" index = list_wc_intra_frame_heap[j];\r\n", +" if ( index == -1 )\r\n", +" {\r\n", +" continue;\r\n", +" }\r\n", +" ptr = &( allocation_list[index] );\r\n", +"\r\n", +" if ( ptr->hash == ptr_record->hash && ptr->wc_heap_size_intra_frame == ptr_record->wc_heap_size_intra_frame )\r\n", +" {\r\n", +" ptr_record->noccurances++;\r\n", +" list_wc_intra_frame_heap[j] = -1;\r\n", +" }\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Print Header */\r\n", +" sprintf( buf, format_str, \"Function Name\", \"Line\", \"Type\", \"Function Parameters\", \"Maximum Size\", \"Usage\" );\r\n", +" puts( buf );\r\n", +" length = strlen( buf );\r\n", +" sprintf( buf, \"%0*d\\n\", (int) length - 1, 0 );\r\n", +" subst( buf, '0', '-' );\r\n", +" puts( buf );\r\n", +"\r\n", +" for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )\r\n", +" {\r\n", +" index_record = list_wc_intra_frame_heap[i];\r\n", +"\r\n", +" if ( index_record != -1 )\r\n", +" {\r\n", +" /* get the record */\r\n", +" ptr_record = &( allocation_list[index_record] );\r\n", +"\r\n", +" /* prepare information strings */\r\n", +" strncpy( name_str, ptr_record->name, MAX_FUNCTION_NAME_LENGTH );\r\n", +" strcat( name_str, \"()\" );\r\n", +" name_str[MAX_FUNCTION_NAME_LENGTH] = '\\0';\r\n", +" strncpy( parms_str, &( ptr_record->params[2] ), MAX_PARAMS_LENGTH );\r\n", +" parms_str[MAX_PARAMS_LENGTH] = '\\0';\r\n", +"\r\n", +" if ( ptr_record->params[0] == 'm' )\r\n", +" {\r\n", +" strcpy( type_str, \"malloc\" );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" strcpy( type_str, \"calloc\" );\r\n", +" }\r\n", +"\r\n", +" sprintf( line_str, \"%d\", ptr_record->lineno );\r\n", +"\r\n", +" /* prepare average usage & memory size strings */\r\n", +" sprintf( usage_str, \"%d%%\", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 1 ) ) * 100.0f ) );\r\n", +"\r\n", +" if ( ptr_record->noccurances > 1 )\r\n", +" {\r\n", +" sprintf( size_str, \"%dx%d %s\", ptr_record->noccurances, (int) ( ptr_record->wc_heap_size_intra_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" sprintf( size_str, \"%d %s\", (int) ( ptr_record->wc_heap_size_intra_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +"\r\n", +" sprintf( buf, format_str, name_str, line_str, type_str, parms_str, size_str, usage_str );\r\n", +" puts( buf );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, \"\\n\" );\r\n", +" }\r\n", +"\r\n", +" if ( n_items_wc_inter_frame_heap > 0 )\r\n", +" {\r\n", +" /* Inter-Frame Heap Size */\r\n", +" fprintf( stdout, \"\\nList of memory blocks when maximum inter-frame heap size is reached:\\n\\n\" );\r\n", +"\r\n", +" /* Find duplicate records (same hash and worst-case heap size) */\r\n", +" for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )\r\n", +" {\r\n", +" index_record = list_wc_inter_frame_heap[i];\r\n", +" if ( index_record == -1 )\r\n", +" {\r\n", +" continue;\r\n", +" }\r\n", +" ptr_record = &( allocation_list[index_record] );\r\n", +" ptr_record->noccurances = 1; /* reset the counter as some blocks may have been both, intra-frame and inter-frame */\r\n", +" for ( j = i + 1; j < n_items_wc_inter_frame_heap; j++ )\r\n", +" {\r\n", +" index = list_wc_inter_frame_heap[j];\r\n", +" if ( index == -1 )\r\n", +" {\r\n", +" continue;\r\n", +" }\r\n", +" ptr = &( allocation_list[index] );\r\n", +"\r\n", +" if ( ptr->hash == ptr_record->hash && ptr->wc_heap_size_inter_frame == ptr_record->wc_heap_size_inter_frame )\r\n", +" {\r\n", +" ptr_record->noccurances++;\r\n", +" list_wc_inter_frame_heap[j] = -1;\r\n", +" }\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" /* Print Header */\r\n", +" sprintf( buf, format_str, \"Function Name\", \"Line\", \"Type\", \"Function Parameters\", \"Memory Size\", \"Usage\" );\r\n", +" puts( buf );\r\n", +" length = strlen( buf );\r\n", +" sprintf( buf, \"%0*d\\n\", (int) length - 1, 0 );\r\n", +" subst( buf, '0', '-' );\r\n", +" puts( buf );\r\n", +"\r\n", +" for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )\r\n", +" {\r\n", +" index_record = list_wc_inter_frame_heap[i];\r\n", +"\r\n", +" if ( index_record != -1 )\r\n", +" {\r\n", +" /* get the record */\r\n", +" ptr_record = &( allocation_list[index_record] );\r\n", +"\r\n", +" /* prepare information strings */\r\n", +" strncpy( name_str, ptr_record->name, MAX_FUNCTION_NAME_LENGTH );\r\n", +" strcat( name_str, \"()\" );\r\n", +" name_str[MAX_FUNCTION_NAME_LENGTH] = '\\0';\r\n", +" strncpy( parms_str, &( ptr_record->params[2] ), MAX_PARAMS_LENGTH );\r\n", +" parms_str[MAX_PARAMS_LENGTH] = '\\0';\r\n", +"\r\n", +" if ( ptr_record->params[0] == 'm' )\r\n", +" {\r\n", +" strcpy( type_str, \"malloc\" );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" strcpy( type_str, \"calloc\" );\r\n", +" }\r\n", +"\r\n", +" sprintf( line_str, \"%d\", ptr_record->lineno );\r\n", +"\r\n", +" /* prepare average usage & memory size strings */\r\n", +" sprintf( usage_str, \"%d%%\", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 0.1f ) ) * 100.0f + 0.5f ) );\r\n", +"\r\n", +" if ( ptr_record->noccurances > 1 )\r\n", +" {\r\n", +" sprintf( size_str, \"%dx%d %s\", ptr_record->noccurances, (int) ( ptr_record->wc_heap_size_inter_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" sprintf( size_str, \"%d %s\", (int) ( ptr_record->wc_heap_size_inter_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +"\r\n", +" sprintf( buf, format_str, name_str, line_str, type_str, parms_str, size_str, usage_str );\r\n", +" puts( buf );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, \"\\n\" );\r\n", +" }\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * print_mem()\r\n", +" *\r\n", +" * Print information about ROM and RAM memory usage\r\n", +" *--------------------------------------------------------------------*/\r\n", +"\r\n", +"void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] )\r\n", +"{\r\n", +" int i, nElem;\r\n", +"\r\n", +" fprintf( stdout, \"\\n\\n --- Memory usage --- \\n\\n\" );\r\n", +"\r\n", +" if ( Const_Data_PROM_Table != NULL )\r\n", +" {\r\n", +" nElem = 0;\r\n", +" while ( strcmp( Const_Data_PROM_Table[nElem].file_spec, \"\" ) != 0 )\r\n", +" nElem++;\r\n", +"\r\n", +" for ( i = 0; i < nElem; i++ )\r\n", +" {\r\n", +" if ( Stat_Cnt_Size > 0 )\r\n", +" {\r\n", +" /* words */\r\n", +" fprintf( stdout, \"Program ROM size (%s): %d words\\n\", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" /* bytes (here, we assume that each instruction takes PROM_INST_SIZE bits of the PROM memory) */\r\n", +" fprintf( stdout, \"Program ROM size (%s): %d bytes\\n\", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size * ( PROM_INST_SIZE / 8 ) );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" for ( i = 0; i < nElem; i++ )\r\n", +" {\r\n", +" if ( Const_Data_PROM_Table[i].Get_Const_Data_Size_Func == NULL )\r\n", +" {\r\n", +" fprintf( stdout, \"Error: Cannot retrieve or calculate Table ROM size of (%s)!\\n\", Const_Data_PROM_Table[i].file_spec );\r\n", +" }\r\n", +"\r\n", +" fprintf( stdout, \"Table ROM (const data) size (%s): %d %s\\n\", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].Get_Const_Data_Size_Func() >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );\r\n", +" }\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" fprintf( stdout, \"Program ROM size: not available\\n\" );\r\n", +" fprintf( stdout, \"Table ROM (const data) size: not available\\n\" );\r\n", +" }\r\n", +"\r\n", +" if ( wc_ram_size > 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum RAM (stack + heap) size: %d %s in frame %d\\n\", wc_ram_size >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size], wc_ram_frame );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum RAM (stack + heap) size: not available\\n\" );\r\n", +" }\r\n", +"\r\n", +" /* check, if the stack is empty */\r\n", +" if ( ptr_current_stack != ptr_base_stack )\r\n", +" {\r\n", +" fprintf( stderr, \"Warning: Stack is not empty.\\n\" );\r\n", +" }\r\n", +"\r\n", +" if ( ptr_base_stack - ptr_max_stack > 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum stack size: %lu %s in frame %d\\n\", ( ( ptr_base_stack - ptr_max_stack ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size],\r\n", +" wc_stack_frame );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum stack size: not available\\n\" );\r\n", +" }\r\n", +"\r\n", +" /* last update of intra-frame memory and inter-frame memory, if needed */\r\n", +" if ( heap_allocation_call_tree_size > 0 )\r\n", +" {\r\n", +" update_mem();\r\n", +" }\r\n", +"\r\n", +" /* check, if all memory blocks have been deallocated (freed) */\r\n", +" for ( i = 0; i < Num_Records; i++ )\r\n", +" {\r\n", +" if ( allocation_list[i].block_ptr != NULL )\r\n", +" {\r\n", +" fprintf( stderr, \"Fct=%s, Ln=%i: %s!\\n\", allocation_list[i].name, allocation_list[i].lineno, \"Error: Memory Block has not been De-Allocated with free()!\" );\r\n", +" exit( -1 );\r\n", +" }\r\n", +" }\r\n", +"\r\n", +" if ( n_items_wc_intra_frame_heap > 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum intra-frame heap size: %d %s in frame %d\\n\", size_wc_intra_frame_heap >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size], location_wc_intra_frame_heap );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum intra-frame heap size: 0\\n\" );\r\n", +" }\r\n", +"\r\n", +" if ( n_items_wc_inter_frame_heap > 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum inter-frame heap size: %d %s in frame %d\\n\", size_wc_inter_frame_heap >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size], location_wc_inter_frame_heap );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" fprintf( stdout, \"Maximum inter-frame heap size: 0\\n\" );\r\n", +" }\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +" /* Print detailed information about worst-case stack usage */\r\n", +" if ( ptr_base_stack - ptr_max_stack > 0 )\r\n", +" {\r\n", +" print_stack_call_tree();\r\n", +" }\r\n", +"\r\n", +" /* Print detailed information about worst-case heap usage */\r\n", +" mem_count_summary();\r\n", +"#endif\r\n", +"\r\n", +" if ( Stat_Cnt_Size > 0 )\r\n", +" {\r\n", +" /* words */\r\n", +" fprintf( stdout, \"\\nNote: The Program ROM size is calculated under the assumption that 1 instruction word is stored with %d bits\\n\", 8 << Stat_Cnt_Size );\r\n", +" }\r\n", +" else\r\n", +" {\r\n", +" /* bytes */\r\n", +" fprintf( stdout, \"\\nNote: The Program ROM size is calculated under the assumption that 1 instruction word is stored with %d bits\\n\", PROM_INST_SIZE );\r\n", +" }\r\n", +" fprintf( stdout, \"Note: The Data ROM size is calculated using the sizeof(type) built-in function\\n\" );\r\n", +"\r\n", +" if ( n_items_wc_intra_frame_heap > 0 )\r\n", +" {\r\n", +" fprintf( stdout, \"Intra-frame heap memory is allocated and de-allocated in the same frame\\n\" );\r\n", +" }\r\n", +"\r\n", +" /* De-allocate list of heap memory blocks */\r\n", +" if ( allocation_list != NULL )\r\n", +" {\r\n", +" free( allocation_list );\r\n", +" }\r\n", +"\r\n", +" /* De-allocate list of stack records */\r\n", +" if ( stack_callers[0] != NULL )\r\n", +" {\r\n", +" free( stack_callers[0] );\r\n", +" }\r\n", +"\r\n", +" if ( stack_callers[1] != NULL )\r\n", +" {\r\n", +" free( stack_callers[1] );\r\n", +" }\r\n", +"\r\n", +" /* De-allocate heap allocation call tree */\r\n", +" if ( heap_allocation_call_tree != NULL )\r\n", +" {\r\n", +" free( heap_allocation_call_tree );\r\n", +" }\r\n", +"\r\n", +" /* De-allocate intra-frame and inter-frame heap lists */\r\n", +" if ( list_wc_intra_frame_heap != NULL )\r\n", +" {\r\n", +" free( list_wc_intra_frame_heap );\r\n", +" }\r\n", +"\r\n", +" if ( list_current_inter_frame_heap != NULL )\r\n", +" {\r\n", +" free( list_current_inter_frame_heap );\r\n", +" }\r\n", +"\r\n", +" if ( list_wc_inter_frame_heap != NULL )\r\n", +" {\r\n", +" free( list_wc_inter_frame_heap );\r\n", +" }\r\n", +"\r\n", +"#ifdef MEM_COUNT_DETAILS\r\n", +" if ( fid_csv_filename != NULL )\r\n", +" {\r\n", +" fclose( fid_csv_filename );\r\n", +" }\r\n", +"#endif\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"#endif /* WMOPS */\r\n", +"\r\n", +"#ifndef WMOPS\r\n", +"int cntr_push_pop = 0; /* global counter for checking balanced push_wmops()/pop_wmops() pairs when WMOPS is not activated */\r\n", +"#endif\r\n", +"\r\n", +"#ifdef WMOPS\r\n", +"/* Global counter for the calculation of BASOP complexity */\r\n", +"BASIC_OP *multiCounter = NULL;\r\n", +"int currCounter = 0;\r\n", +"int funcId_where_last_call_to_else_occurred;\r\n", +"long funcid_total_wmops_at_last_call_to_else;\r\n", +"int call_occurred = 1;\r\n", +"\r\n", +"BASIC_OP op_weight = {\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 1, 1, 2, 2, 1,\r\n", +" 1, 1, 1, 3, 1,\r\n", +"\r\n", +" 1, 1, 1, 3, 1,\r\n", +" 4, 1, 18, 1, 1,\r\n", +" 2, 1, 2, 2, 1,\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 3, 3, 3, 3, 1,\r\n", +"\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 1, 1, 1, 2,\r\n", +" 1, 2, 2, 4, 1,\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 1, 1, 1, 1, 1,\r\n", +"\r\n", +" 1, 1, 1, 1, 3,\r\n", +" 3, 3, 3, 3, 1,\r\n", +" 1, 1, 1, 1, 1,\r\n", +" 1, 1, 1, 4, 4,\r\n", +" 4, 8, 3, 4, 4,\r\n", +"\r\n", +" 5, 32, 3\r\n", +"};\r\n", +"\r\n", +"/* Set the counter group to use, default is zero */\r\n", +"void Set_BASOP_WMOPS_counter( int counterId )\r\n", +"{\r\n", +" if ( ( counterId > num_wmops_records ) || ( counterId < 0 ) )\r\n", +" {\r\n", +" currCounter = 0;\r\n", +" return;\r\n", +" }\r\n", +" currCounter = counterId;\r\n", +" call_occurred = 1;\r\n", +"}\r\n", +"\r\n", +"extern int32_t frame;\r\n", +"\r\n", +"long TotalWeightedOperation()\r\n", +"{\r\n", +" int i;\r\n", +" unsigned int *ptr, *ptr2;\r\n", +" long tot; \r\n", +"\r\n", +" tot = 0;\r\n", +" ptr = (unsigned int *) &multiCounter[currCounter];\r\n", +" ptr2 = (unsigned int *) &op_weight;\r\n", +"\r\n", +" for ( i = 0; i < ( int )( sizeof( multiCounter[currCounter] ) / sizeof( unsigned int ) ); i++ )\r\n", +" {\r\n", +" tot += ( ( *ptr++ ) * ( *ptr2++ ) );\r\n", +" }\r\n", +"\r\n", +" return ( tot );\r\n", +"}\r\n", +"\r\n", +"long DeltaWeightedOperation( void )\r\n", +"{\r\n", +" long NewWOper, delta;\r\n", +"\r\n", +" NewWOper = TotalWeightedOperation();\r\n", +"\r\n", +" delta = NewWOper - wmops[currCounter].LastWOper;\r\n", +" wmops[currCounter].LastWOper = NewWOper;\r\n", +"\r\n", +" return ( delta );\r\n", +"}\r\n", +"\r\n", +"/* Resets the current BASOP WMOPS counter */\r\n", +"void Reset_BASOP_WMOPS_counter( void )\r\n", +"{\r\n", +" int i;\r\n", +" long *ptr;\r\n", +"\r\n", +" /* clear the current BASOP operation counter before new frame begins */\r\n", +" ptr = (long *) &multiCounter[currCounter];\r\n", +" for ( i = 0; i < (int) ( sizeof( multiCounter[currCounter] ) / sizeof( long ) ); i++ )\r\n", +" {\r\n", +" *ptr++ = 0;\r\n", +" }\r\n", +"\r\n", +" wmops[currCounter].LastWOper = 0;\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"\r\n", +"\r\n", \ No newline at end of file diff --git a/src/wmc_tool/wmc_auto_h.txt b/src/wmc_tool/wmc_auto_h.txt index a5d54b3..caed270 100644 --- a/src/wmc_tool/wmc_auto_h.txt +++ b/src/wmc_tool/wmc_auto_h.txt @@ -1,1044 +1,1448 @@ -"/*\r\n" -" * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved.\r\n" -" *\r\n" -" * This software is protected by copyright law and by international treaties. The source code, and all of its derivations,\r\n" -" * is provided by VoiceAge Corporation under the \"ITU-T Software Tools' General Public License\". Please, read the license file\r\n" -" * or refer to ITU-T Recommendation G.191 on \"SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS\".\r\n" -" *\r\n" -" * Any use of this software is permitted provided that this notice is not removed and that neither the authors nor\r\n" -" * VoiceAge Corporation are deemed to have made any representations as to the suitability of this software\r\n" -" * for any purpose nor are held responsible for any defects of this software. THERE IS NO WARRANTY FOR THIS SOFTWARE.\r\n" -" *\r\n" -" * Authors: Guy Richard, Vladimir Malenovsky (Vladimir.Malenovsky@USherbrooke.ca)\r\n" -" */\r\n" -"\r\n" -"#ifndef WMOPS_H\r\n" -"#define WMOPS_H\r\n" -"\r\n" -"#ifndef EXIT_FAILURE\r\n" -"#include /* stdlib is needed for exit() */\r\n" -"#endif\r\n" -"\r\n" -"#ifndef EOF\r\n" -"#include /* stdio is needed for fprintf() */\r\n" -"#endif\r\n" -"\r\n" -"\r\n" -"/* To Prevent \"warning: '$' in identifier or number\" message under GCC */\r\n" -"#ifdef __GNUC__\r\n" -"#pragma GCC system_header\r\n" -"#endif\r\n" -"\r\n" -"/* Real-time relationships */\r\n" -"#define FRAMES_PER_SECOND 50.0\r\n" -"#define MILLION_CYCLES 1e6\r\n" -"#define WMOPS_BOOST_FAC ( 1.0f ) /* scaling factor for equalizing the difference between automatic and manual instrumentation */\r\n" -"#define FAC ( FRAMES_PER_SECOND / MILLION_CYCLES * WMOPS_BOOST_FAC )\r\n" -"#define NUM_INST 20 /* Total number of instruction types (in enum below) */\r\n" -"\r\n" -"\r\n" -"#ifdef WMOPS\r\n" -"enum instructions\r\n" -"{\r\n" -" _ADD,\r\n" -" _ABS,\r\n" -" _MULT,\r\n" -" _MAC,\r\n" -" _MOVE,\r\n" -" _STORE,\r\n" -" _LOGIC,\r\n" -" _SHIFT,\r\n" -" _BRANCH,\r\n" -" _DIV,\r\n" -" _SQRT,\r\n" -" _TRANS,\r\n" -" _FUNC,\r\n" -" _LOOP,\r\n" -" _INDIRECT,\r\n" -" _PTR_INIT,\r\n" -" _TEST,\r\n" -" _POWER,\r\n" -" _LOG,\r\n" -" _MISC\r\n" -"};\r\n" -"\r\n" -"#define _ADD_C 1\r\n" -"#define _ABS_C 1\r\n" -"#define _MULT_C 1\r\n" -"#define _MAC_C 1\r\n" -"#define _MOVE_C 1\r\n" -"#define _STORE_C 1\r\n" -"#define _LOGIC_C 1\r\n" -"#define _SHIFT_C 1\r\n" -"#define _BRANCH_C 4\r\n" -"#define _DIV_C 18\r\n" -"#define _SQRT_C 10\r\n" -"#define _TRANS_C 25\r\n" -"#define _FUNC_C 2 /* need to add number of arguments */\r\n" -"#define _LOOP_C 3\r\n" -"#define _INDIRECT_C 2\r\n" -"#define _PTR_INIT_C 1\r\n" -"#define _TEST_C 2\r\n" -"#define _POWER_C 25\r\n" -"#define _LOG_C 25\r\n" -"#define _MISC_C 1\r\n" -"\r\n" -"#define _ADD_P 1\r\n" -"#define _ABS_P 1\r\n" -"#define _MULT_P 1\r\n" -"#define _MAC_P 1\r\n" -"#define _MOVE_P 1\r\n" -"#define _STORE_P 0\r\n" -"#define _LOGIC_P 1\r\n" -"#define _SHIFT_P 1\r\n" -"#define _BRANCH_P 2\r\n" -"#define _DIV_P 2\r\n" -"#define _SQRT_P 2\r\n" -"#define _TRANS_P 2\r\n" -"#define _FUNC_P 2 /* need to add number of arguments */\r\n" -"#define _LOOP_P 1\r\n" -"#define _INDIRECT_P 2\r\n" -"#define _PTR_INIT_P 1\r\n" -"#define _TEST_P 1\r\n" -"#define _POWER_P 2\r\n" -"#define _LOG_P 2\r\n" -"#define _MISC_P 1\r\n" -"\r\n" -"#define ADD( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _ADD_C * ( x ) ); \\\r\n" -" inst_cnt[_ADD] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _ADD_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define ABS( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _ABS_C * ( x ) ); \\\r\n" -" inst_cnt[_ABS] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _ABS_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define MULT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _MULT_C * ( x ) ); \\\r\n" -" inst_cnt[_MULT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MULT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define MAC( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _MAC_C * ( x ) ); \\\r\n" -" inst_cnt[_MAC] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MAC_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define MOVE( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _MOVE_C * ( x ) ); \\\r\n" -" inst_cnt[_MOVE] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MOVE_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define STORE( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _STORE_C * ( x ) ); \\\r\n" -" inst_cnt[_STORE] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _STORE_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define LOGIC( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _LOGIC_C * ( x ) ); \\\r\n" -" inst_cnt[_LOGIC] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _LOGIC_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define SHIFT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _SHIFT_C * ( x ) ); \\\r\n" -" inst_cnt[_SHIFT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _SHIFT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define BRANCH( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _BRANCH_C * ( x ) ); \\\r\n" -" inst_cnt[_BRANCH] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _BRANCH_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DIV( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _DIV_C * ( x ) ); \\\r\n" -" inst_cnt[_DIV] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _DIV_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define SQRT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _SQRT_C * ( x ) ); \\\r\n" -" inst_cnt[_SQRT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _SQRT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define TRANS( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _TRANS_C * ( x ) ); \\\r\n" -" inst_cnt[_TRANS] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _TRANS_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define LOOP( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _LOOP_C * ( x ) ); \\\r\n" -" inst_cnt[_LOOP] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _LOOP_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define INDIRECT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _INDIRECT_C * ( x ) ); \\\r\n" -" inst_cnt[_INDIRECT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _INDIRECT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define PTR_INIT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _PTR_INIT_C * ( x ) ); \\\r\n" -" inst_cnt[_PTR_INIT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _PTR_INIT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define TEST( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _TEST_C * ( x ) ); \\\r\n" -" inst_cnt[_TEST] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _TEST_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define POWER( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _POWER_C * ( x ) ); \\\r\n" -" inst_cnt[_POWER] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _POWER_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define LOG( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _LOG_C * ( x ) ); \\\r\n" -" inst_cnt[_LOG] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _LOG_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define MISC( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _MISC_C * ( x ) ); \\\r\n" -" inst_cnt[_MISC] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MISC_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"\r\n" -"#define FUNC( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( _FUNC_C + _MOVE_C * ( x ) ); \\\r\n" -" inst_cnt[_FUNC]++; \\\r\n" -" inst_cnt[_MOVE] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _FUNC_P + _MOVE_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"\r\n" -"#define DADD( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _ADD_C * ( x ) ); \\\r\n" -" inst_cnt[_ADD] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _ADD_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DMULT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _MULT_C * ( x ) ); \\\r\n" -" inst_cnt[_MULT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MULT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DMAC( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _MAC_C * ( x ) ); \\\r\n" -" inst_cnt[_MAC] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MAC_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DMOVE( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _MOVE_C * ( x ) ); \\\r\n" -" inst_cnt[_MOVE] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _MOVE_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DSTORE( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _STORE_C * ( x ) ); \\\r\n" -" inst_cnt[_STORE] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _STORE_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DLOGIC( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _LOGIC_C * ( x ) ); \\\r\n" -" inst_cnt[_LOGIC] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _LOGIC_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DSHIFT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _SHIFT_C * ( x ) ); \\\r\n" -" inst_cnt[_SHIFT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _SHIFT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DDIV( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _DIV_C * ( x ) ); \\\r\n" -" inst_cnt[_DIV] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _DIV_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DSQRT( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _SQRT_C * ( x ) ); \\\r\n" -" inst_cnt[_SQRT] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _SQRT_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"#define DTRANS( x ) \\\r\n" -" { \\\r\n" -" { \\\r\n" -" ops_cnt += ( 2 * _TRANS_C * ( x ) ); \\\r\n" -" inst_cnt[_TRANS] += ( x ); \\\r\n" -" { \\\r\n" -" static int pcnt; \\\r\n" -" if ( !pcnt ) \\\r\n" -" { \\\r\n" -" pcnt = 1; \\\r\n" -" prom_cnt += ( _TRANS_P * ( x ) ); \\\r\n" -" } \\\r\n" -" } \\\r\n" -" } \\\r\n" -" }\r\n" -"\r\n" -"extern double ops_cnt;\r\n" -"extern double prom_cnt;\r\n" -"extern double inst_cnt[NUM_INST];\r\n" -"extern int ops_cnt_activ;\r\n" -"\r\n" -"void reset_wmops( void );\r\n" -"void push_wmops( const char *label );\r\n" -"void pop_wmops( void );\r\n" -"void update_wmops( void );\r\n" -"void update_mem( void );\r\n" -"void print_wmops( void );\r\n" -"\r\n" -"#else /* WMOPS counting disabled */\r\n" -"\r\n" -"#define reset_wmops()\r\n" -"extern int cntr_push_pop;\r\n" -"#define push_wmops( x ) ( cntr_push_pop++ )\r\n" -"#define pop_wmops() ( cntr_push_pop-- )\r\n" -"#define update_wmops() ( assert( cntr_push_pop == 0 ) )\r\n" -"#define update_mem()\r\n" -"#define print_wmops()\r\n" -"\r\n" -"#define ADD( x )\r\n" -"#define ABS( x )\r\n" -"#define MULT( x )\r\n" -"#define MAC( x )\r\n" -"#define MOVE( x )\r\n" -"#define STORE( x )\r\n" -"#define LOGIC( x )\r\n" -"#define SHIFT( x )\r\n" -"#define BRANCH( x )\r\n" -"#define DIV( x )\r\n" -"#define SQRT( x )\r\n" -"#define TRANS( x )\r\n" -"#define FUNC( x )\r\n" -"#define LOOP( x )\r\n" -"#define INDIRECT( x )\r\n" -"#define PTR_INIT( x )\r\n" -"#define TEST( x )\r\n" -"#define POWER( x )\r\n" -"#define LOG( x )\r\n" -"#define MISC( x )\r\n" -"\r\n" -"#define DADD( x )\r\n" -"#define DMULT( x )\r\n" -"#define DMAC( x )\r\n" -"#define DMOVE( x )\r\n" -"#define DSTORE( x )\r\n" -"#define DLOGIC( x )\r\n" -"#define DSHIFT( x )\r\n" -"#define DDIV( x )\r\n" -"#define DSQRT( x )\r\n" -"#define DTRANS( x )\r\n" -"\r\n" -"#endif\r\n" -"\r\n" -"/* mac & msu (Non Instrumented Versions) */\r\n" -"#ifndef mac\r\n" -"#define mac( a, b, c ) ( ( a ) + ( b ) * ( c ) )\r\n" -"#endif\r\n" -"#ifndef mac\r\n" -"#define msu( a, b, c ) ( ( a ) - ( b ) * ( c ) )\r\n" -"#endif\r\n" -"\r\n" -"#ifndef WMOPS\r\n" -"/* DESACTIVATE the Counting Mechanism */\r\n" -"#define OP_COUNT_( op, n )\r\n" -"\r\n" -"/* DESACTIVATE Operation Counter Wrappers */\r\n" -"#define OP_COUNT_WRAPPER1_( op, val ) ( val )\r\n" -"#define OP_COUNT_WRAPPER2_( expr )\r\n" -"#define OP_COUNT_WRAPPER3_( op, expr ) expr\r\n" -"\r\n" -"/* DESACTIVATE Logical & Ternary Operators */\r\n" -"#define __\r\n" -"#define _\r\n" -"\r\n" -"#else\r\n" -"\r\n" -"/* '*ops_cnt_ptr' is Used to Avoid: \"warning: operation on 'ops_cnt' may be undefined\" with Cygwin gcc Compiler */\r\n" -"static double *ops_cnt_ptr = &ops_cnt;\r\n" -"#define OP_COUNT_( op, x ) ( *ops_cnt_ptr += ( op##_C * ( x ) ), inst_cnt[op] += ( x ) )\r\n" -"\r\n" -"/******************************************************************/\r\n" -"/* NOTES: */\r\n" -"/* The 'wmc_flag_' flag is global to avoid declaration in every */\r\n" -"/* function and 'static' to avoid clashing with other modules */\r\n" -"/* that include this header file. */\r\n" -"/* */\r\n" -"/* The declarations of 'wmc_flag_' and 'wops_' in this header */\r\n" -"/* file prevent the addition of a 'C' file to the Project. */\r\n" -"/******************************************************************/\r\n" -"\r\n" -"/* General Purpose Global Flag */\r\n" -"static int wmc_flag_ = 0;\r\n" -"\r\n" -"/* Operation Counter Wrappers */\r\n" -"#define OP_COUNT_WRAPPER1_( op, val ) ( op, val )\r\n" -"#define OP_COUNT_WRAPPER2_( expr ) \\\r\n" -" if ( expr, 0 ) \\\r\n" -" ; \\\r\n" -" else\r\n" -"#define OP_COUNT_WRAPPER3_( op, expr ) \\\r\n" -" if ( op, 0 ) \\\r\n" -" ; \\\r\n" -" else \\\r\n" -" expr\r\n" -"\r\n" -"#endif\r\n" -"\r\n" -"/* Define all Macros without '{' & '}' (None of these should be called externally!) */\r\n" -"#define ABS_( x ) OP_COUNT_( _ABS, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define ADD_( x ) OP_COUNT_( _ADD, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define MULT_( x ) OP_COUNT_( _MULT, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define MAC_( x ) OP_COUNT_( _MAC, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define MOVE_( x ) OP_COUNT_( _MOVE, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define STORE_( x ) OP_COUNT_( _STORE, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define LOGIC_( x ) OP_COUNT_( _LOGIC, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define SHIFT_( x ) OP_COUNT_( _SHIFT, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define BRANCH_( x ) OP_COUNT_( _BRANCH, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define DIV_( x ) OP_COUNT_( _DIV, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define SQRT_( x ) OP_COUNT_( _SQRT, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define TRANS_( x ) OP_COUNT_( _TRANS, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define POWER_( x ) TRANS_( x )\r\n" -"#define LOG_( x ) TRANS_( x )\r\n" -"#define LOOP_( x ) OP_COUNT_( _LOOP, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define INDIRECT_( x ) OP_COUNT_( _INDIRECT, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define PTR_INIT_( x ) OP_COUNT_( _PTR_INIT, ( x ) / WMOPS_BOOST_FAC )\r\n" -"#define FUNC_( x ) ( OP_COUNT_( _MOVE, ( x ) / WMOPS_BOOST_FAC ), OP_COUNT_( _FUNC, 1 ) )\r\n" -"#define MISC_( x ) ABS_( x )\r\n" -"\r\n" -"/* Math Operations */\r\n" -"#define abs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), abs )\r\n" -"#define fabs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), fabs )\r\n" -"#define labs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), labs )\r\n" -"#define floor_ OP_COUNT_WRAPPER1_( MISC_( 1 ), floor )\r\n" -"#define sqrt_ OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrt )\r\n" -"#define pow_ OP_COUNT_WRAPPER1_( POWER_( 1 ), pow )\r\n" -"#define exp_ OP_COUNT_WRAPPER1_( POWER_( 1 ), exp )\r\n" -"#define log_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log )\r\n" -"#define log10_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log10 )\r\n" -"#define cos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cos )\r\n" -"#define sin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sin )\r\n" -"#define tan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tan )\r\n" -"#define acos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), acos )\r\n" -"#define asin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), asin )\r\n" -"#define atan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan )\r\n" -"#define atan2_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan2 )\r\n" -"#define cosh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cosh )\r\n" -"#define sinh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinh )\r\n" -"#define tanh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanh )\r\n" -"#define fmod_ OP_COUNT_WRAPPER1_( DIV_( 1 ), fmod )\r\n" -"/* these macros use any local macros already defined */\r\n" -"/* min/max and their Variants */\r\n" -"#define min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), min( ( a ), ( b ) ) )\r\n" -"#define max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), max( ( a ), ( b ) ) )\r\n" -"#define MIN_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MIN( ( a ), ( b ) ) )\r\n" -"#define MAX_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MAX( ( a ), ( b ) ) )\r\n" -"#define Min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Min( ( a ), ( b ) ) )\r\n" -"#define Max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Max( ( a ), ( b ) ) )\r\n" -"/* Square and its Variants */\r\n" -"#define sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), sqr( ( x ) ) )\r\n" -"#define Sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Sqr( ( x ) ) )\r\n" -"#define SQR_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQR( ( x ) ) )\r\n" -"#define square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), square( ( x ) ) )\r\n" -"#define Square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Square( ( x ) ) )\r\n" -"#define SQUARE_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQUARE( ( x ) ) )\r\n" -"/* Sign and its Variants */\r\n" -"#define sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), sign( ( x ) ) )\r\n" -"#define Sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), Sign( ( x ) ) )\r\n" -"#define SIGN_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), SIGN( ( x ) ) )\r\n" -"/* Square Root and its Variants */\r\n" -"#define sqrtf_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrtf( ( x ) ) )\r\n" -"/* Invert Square Root and its Variants */\r\n" -"#define inv_sqrt_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), inv_sqrt( ( x ) ) )\r\n" -"/* Others */\r\n" -"#define log_base_2_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log_base_2( ( x ) ) )\r\n" -"#define log2_f_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2_f( ( x ) ) )\r\n" -"/* The 'wmc_flag_=wmc_flag_' is Used to Avoid: \"warning: left-hand operand of comma expression has no effect\"\r\n" -" with Cygwin gcc Compiler */\r\n" -"#define _round_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, _round( ( x ) ) )\r\n" -"#define round_f_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, round_f( ( x ) ) )\r\n" -"#define _squant_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, _squant( ( x ) ) )\r\n" -"/* Set Min/Max */\r\n" -"#define set_min_( a, b ) OP_COUNT_WRAPPER3_( ( ADD_( 1 ), BRANCH_( 1 ), MOVE_( 1 ) ), set_min( ( a ), ( b ) ) )\r\n" -"#define set_max_( a, b ) OP_COUNT_WRAPPER3_( ( ADD_( 1 ), BRANCH_( 1 ), MOVE_( 1 ) ), set_max( ( a ), ( b ) ) )\r\n" -"/* mac & msu (Instrumented Versions) */\r\n" -"#define mac_( a, b, c ) OP_COUNT_WRAPPER1_( MAC_( 1 ), mac( a, b, c ) )\r\n" -"#define msu_( a, b, c ) OP_COUNT_WRAPPER1_( MAC_( 1 ), msu( a, b, c ) )\r\n" -"\r\n" -"/* Functions */\r\n" -"#define func_( name, x ) OP_COUNT_WRAPPER1_( FUNC_( x ), name )\r\n" -"\r\n" -"/* Logical Operators */\r\n" -"#ifndef __\r\n" -"#define __ ( BRANCH_( 1 ), 1 ) &&\r\n" -"#endif\r\n" -"\r\n" -"/* Ternary Operators (? and :) */\r\n" -"#ifndef _\r\n" -"#define _ ( BRANCH_( 1 ), 0 ) ? 0:\r\n" -"#endif\r\n" -"\r\n" -"/* Flow Control keywords */\r\n" -"#define if_ \\\r\n" -" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n" -" if\r\n" -"#define for_ OP_COUNT_WRAPPER2_( LOOP_(1)) for\r\n" -"#define while_( c ) \\\r\n" -" while \\\r\n" -" OP_COUNT_WRAPPER1_( BRANCH_( 1 ), ( c ) ) /* needs extra \"()\" if ',' encountered */\r\n" -"#define do_ \\\r\n" -" do \\\r\n" -" {\r\n" -"#define _while \\\r\n" -" BRANCH_( 1 ); \\\r\n" -" } \\\r\n" -" while\r\n" -"\r\n" -"#define goto_ \\\r\n" -" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n" -" goto\r\n" -"#define break_ \\\r\n" -" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n" -" break\r\n" -"#define continue_ \\\r\n" -" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n" -" continue\r\n" -"#define return_ \\\r\n" -" OP_COUNT_WRAPPER2_( ( wmc_flag_ = stack_tree_level_, STACK_DEPTH_FCT_RETURN ) ) \\\r\n" -" return\r\n" -"\r\n" -"#define switch_ \\\r\n" -" OP_COUNT_WRAPPER2_( ( BRANCH_( 1 ), wmc_flag_ = 1 ) ) \\\r\n" -" switch\r\n" -"#define cost_( n ) OP_COUNT_WRAPPER2_( wmc_flag_ ? ( ADD_( n ), BRANCH_( n ), wmc_flag_ = 0 ) : 0 );\r\n" -"\r\n" -"#ifdef WMOPS\r\n" -"\r\n" -"#define ACC 2\r\n" -"#define MUL 1\r\n" -"\r\n" -"/* Counting Function (should not be called externally!) */\r\n" -"static void wops_( const char *ops )\r\n" -"{\r\n" -" char lm = 0; /* lm: Last Operation is Math */\r\n" -" static char lo = 0; /* Last Operation */\r\n" -"\r\n" -" void ( *fct )( const char *ops ) = wops_;\r\n" -"\r\n" -"st:\r\n" -" while ( *ops != '\\0' )\r\n" -" {\r\n" -" switch ( *ops++ )\r\n" -" {\r\n" -" int cnt;\r\n" -" case '-':\r\n" -" for ( cnt = 0; ops[cnt] == '>'; cnt++ )\r\n" -" ;\r\n" -" if ( cnt & 1 )\r\n" -" goto ind;\r\n" -" case '+':\r\n" -" lm = 2;\r\n" -" if ( lo & MUL )\r\n" -" {\r\n" -" MULT_( -1 );\r\n" -" MAC_( 1 );\r\n" -" break;\r\n" -" }\r\n" -" lo = ACC << 2;\r\n" -" case 'U':\r\n" -" case 'D':\r\n" -" ADD_( 1 );\r\n" -" break;\r\n" -" case '*':\r\n" -" lm = 2;\r\n" -" if ( lo & ACC )\r\n" -" {\r\n" -" ADD_( -1 );\r\n" -" MAC_( 1 );\r\n" -" break;\r\n" -" }\r\n" -" lo = MUL << 2;\r\n" -" MULT_( 1 );\r\n" -" break;\r\n" -" case '/':\r\n" -" case '%':\r\n" -" lm = 2;\r\n" -" DIV_( 1 );\r\n" -" break;\r\n" -" case '&':\r\n" -" case '|':\r\n" -" case '^':\r\n" -" lm = 2;\r\n" -" case '~':\r\n" -" LOGIC_( 1 );\r\n" -" break;\r\n" -" case '<':\r\n" -" case '>':\r\n" -" if ( *ops != ops[-1] )\r\n" -" goto error;\r\n" -" ops++;\r\n" -" case -85:\r\n" -" case -69:\r\n" -" lm = 2;\r\n" -" SHIFT_( 1 );\r\n" -" break;\r\n" -" case 'L':\r\n" -" case 'G':\r\n" -" if ( *ops == 't' )\r\n" -" goto comp;\r\n" -" case 'E':\r\n" -" case 'N':\r\n" -" if ( *ops != 'e' )\r\n" -" goto error;\r\n" -" comp:\r\n" -" ops++;\r\n" -" ADD_( 1 );\r\n" -" break;\r\n" -" case '!':\r\n" -" MISC_( 2 );\r\n" -" break;\r\n" -" case 'M':\r\n" -" MOVE_( 1 );\r\n" -" break;\r\n" -" case 'S':\r\n" -" STORE_( 1 );\r\n" -" break;\r\n" -" case 'P':\r\n" -" PTR_INIT_( 1 );\r\n" -" break;\r\n" -" case '[':\r\n" -" case ']':\r\n" -" goto st;\r\n" -" ind:\r\n" -" ops++;\r\n" -" case 'I':\r\n" -" case '.':\r\n" -" INDIRECT_( 1 );\r\n" -" break;\r\n" -" case '=':\r\n" -" if ( lm )\r\n" -" goto st;\r\n" -" case '\\0':\r\n" -" /* This Shouldn't Happen */\r\n" -" /* These are Used to Avoid: \"warning: 'name' defined but not used\" with Cygwin gcc Compiler */\r\n" -" wmc_flag_ = wmc_flag_;\r\n" -" ops_cnt_ptr = ops_cnt_ptr;\r\n" -" fct( \"\" );\r\n" -" error:\r\n" -" default:\r\n" -" fprintf( stderr, \"\\r wops: Invalid Counting Operation '%s'\\n\", ops - 1 );\r\n" -" exit( -1 );\r\n" -" }\r\n" -" lm >>= 1;\r\n" -" lo >>= 2;\r\n" -" }\r\n" -"\r\n" -" return;\r\n" -"}\r\n" -"\r\n" -"#endif\r\n" -"\r\n" -"/* All Other Operations */\r\n" -"#define $( str ) OP_COUNT_WRAPPER2_( wops_( str ) )\r\n" -"\r\n" -"\r\n" -"/*-------------------------------------------------------------------*\r\n" -" * Memory counting tool\r\n" -" *-------------------------------------------------------------------*/\r\n" -"\r\n" -"/* Enhanced Const Data Size Counting (Rounding Up to the Nearest 'Integer' Size) */\r\n" -"#define rsize( item ) ( ( sizeof( item ) + sizeof( int ) - 1 ) / sizeof( int ) * sizeof( int ) )\r\n" -"\r\n" -"#ifdef _MSC_VER\r\n" -"/* Disable \"warning C4210: nonstandard extension used : function given file scope\" with Visual Studio Compiler */\r\n" -"#pragma warning( disable : 4210 )\r\n" -"#endif\r\n" -"\r\n" -"/* Const Data Size and PROM Size Wrapper Functions */\r\n" -"#define Const_Data_Size_Func( file ) Const_Data_Size_##file( void )\r\n" -"#define Get_Const_Data_Size( file, val_ptr ) \\\r\n" -" { \\\r\n" -" extern int Const_Data_Size_##file( void ); \\\r\n" -" *( val_ptr ) = Const_Data_Size_##file(); \\\r\n" -" }\r\n" -"#define PROM_Size_Func( file ) PROM_Size_##file( void )\r\n" -"#define Get_PROM_Size( file, val_ptr ) \\\r\n" -" { \\\r\n" -" int PROM_Size_##file( void ); \\\r\n" -" *( val_ptr ) = PROM_Size_##file(); \\\r\n" -" }\r\n" -"\r\n" -"/* ROM Size Lookup Table - contains information about PROM size and Const Data Size in all source files */\r\n" -"/* The print_mem() function looks for this table to print the results of Const Data usage and PROM usage */\r\n" -"typedef struct ROM_Size_Lookup_Table\r\n" -"{\r\n" -" const char file_spec[255];\r\n" -" int PROM_size;\r\n" -" int ( *Get_Const_Data_Size_Func )( void );\r\n" -"} ROM_Size_Lookup_Table;\r\n" -"\r\n" -"/* The WMC tool inserts the following declaration during the innstrumentation process in the .c file where the function print_mem() is located */\r\n" -"/* and modifies it to print_mem(Const_Data_PROM_Table) */\r\n" -"\r\n" -"/* #ifdef WMOPS\r\n" -" * ROM_Size_Lookup_Table Const_Data_PROM_Table[] =\r\n" -" * {\r\n" -" * {\"../lib_enc/rom_enc.c\", 0, NULL},\r\n" -" * {\"../lib_com/*.c\", 0, NULL},\r\n" -" * {\"\", -1, NULL}\r\n" -" * };\r\n" -" * #endif\r\n" -" */\r\n" -"\r\n" -"/*#define MEM_ALIGN_64BITS */ /* Define this when using 64 Bits values in the code (ex: double), otherwise it will align on 32 Bits */\r\n" -"/*#define MEM_COUNT_DETAILS*/\r\n" -"\r\n" -"typedef enum\r\n" -"{\r\n" -" USE_BYTES = 0,\r\n" -" USE_16BITS = 1,\r\n" -" USE_32BITS = 2\r\n" -"} Counting_Size;\r\n" -"\r\n" -"#if ( defined( _WIN32 ) && ( _MSC_VER <= 1800 ) && ( _MSC_VER >= 1300 ) )\r\n" -"#define __func__ __FUNCTION__\r\n" -"#elif defined( __STDC_VERSION__ ) && __STDC_VERSION__ < 199901L\r\n" -"#if ( __GNUC__ >= 2 )\r\n" -"#define __func__ __FUNCTION__\r\n" -"#else\r\n" -"#define __func__ \"\"\r\n" -"#endif\r\n" -"#elif defined( __GNUC__ )\r\n" -"#define __func__ __extension__ __FUNCTION__\r\n" -"#endif\r\n" -"\r\n" -"\r\n" -"#ifdef WMOPS\r\n" -"\r\n" -"void *mem_alloc( const char *func_name, int func_lineno, size_t size, char *alloc_str );\r\n" -"void mem_free( const char *func_name, int func_lineno, void *ptr );\r\n" -"\r\n" -"#define malloc_( size ) mem_alloc( __func__, __LINE__, size, \"m:\" #size )\r\n" -"#define calloc_( n, size ) mem_alloc( __func__, __LINE__, ( n ) * ( size ), \"c:\" #n \", \" #size )\r\n" -"#define free_( ptr ) mem_free( __func__, __LINE__, ptr )\r\n" -"\r\n" -"void reset_mem( Counting_Size cnt_size );\r\n" -"void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] );\r\n" -"#ifdef MEM_COUNT_DETAILS\r\n" -"void export_mem( const char *csv_filename );\r\n" -"#endif\r\n" -"\r\n" -"int push_stack( const char *filename, const char *fctname );\r\n" -"int pop_stack( const char *filename, const char *fctname );\r\n" -"\r\n" -"#ifdef WMOPS_DETAIL\r\n" -"#define STACK_DEPTH_FCT_CALL ( push_wmops( __FUNCTION__ ), push_stack( __FILE__, __FUNCTION__ ) ) /* add push_wmops() in all function calls */\r\n" -"#define STACK_DEPTH_FCT_RETURN ( pop_wmops(), pop_stack( __FILE__, __FUNCTION__ ) ) /* add pop_wmops() in all function returns */\r\n" -"#else\r\n" -"#define STACK_DEPTH_FCT_CALL push_stack( __FILE__, __FUNCTION__ )\r\n" -"#define STACK_DEPTH_FCT_RETURN pop_stack( __FILE__, __FUNCTION__ )\r\n" -"#endif\r\n" -"\r\n" -"void reset_stack( void );\r\n" -"#define func_start_ int stack_tree_level_ = STACK_DEPTH_FCT_CALL;\r\n" -"\r\n" -"#else\r\n" -"#define malloc_( n1 ) malloc( n1 )\r\n" -"#define calloc_( n1, n2 ) calloc( n1, n2 )\r\n" -"#define free_( ptr ) free( ptr )\r\n" -"#define reset_mem( cnt_size )\r\n" -"#define print_mem( Const_Data_PROM_Table )\r\n" -"#define export_mem( csv_filename )\r\n" -"\r\n" -"#define push_stack( file, fct )\r\n" -"#define pop_stack( file, fct )\r\n" -"#define reset_stack()\r\n" -"#define func_start_\r\n" -"\r\n" -"#endif\r\n" -"\r\n" -"#endif /* WMOPS_H */\r\n" -"\r\n" \ No newline at end of file +"/*\r\n", +" * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved.\r\n", +" *\r\n", +" * This software is protected by copyright law and by international treaties. The source code, and all of its derivations,\r\n", +" * is provided by VoiceAge Corporation under the \"ITU-T Software Tools' General Public License\". Please, read the license file\r\n", +" * or refer to ITU-T Recommendation G.191 on \"SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS\".\r\n", +" *\r\n", +" * Any use of this software is permitted provided that this notice is not removed and that neither the authors nor\r\n", +" * VoiceAge Corporation are deemed to have made any representations as to the suitability of this software\r\n", +" * for any purpose nor are held responsible for any defects of this software. THERE IS NO WARRANTY FOR THIS SOFTWARE.\r\n", +" *\r\n", +" * Authors: Guy Richard, Vladimir Malenovsky (Vladimir.Malenovsky@USherbrooke.ca)\r\n", +" */\r\n", +"\r\n", +"#ifndef WMOPS_H\r\n", +"#define WMOPS_H\r\n", +"\r\n", +"#ifndef EXIT_FAILURE\r\n", +"#include /* stdlib is needed for exit() */\r\n", +"#endif\r\n", +"\r\n", +"#ifndef EOF\r\n", +"#include /* stdio is needed for fprintf() */\r\n", +"#endif\r\n", +"\r\n", +"\r\n", +"/* To Prevent \"warning: '$' in identifier or number\" message under GCC */\r\n", +"#ifdef __GNUC__\r\n", +"#pragma GCC system_header\r\n", +"#endif\r\n", +"\r\n", +"#ifndef INT_MAX\r\n", +"#define INT_MAX 32767\r\n", +"#endif\r\n", +"\r\n", +"#define FRAMES_PER_SECOND 50.0 \r\n", +"#define PROM_INST_SIZE 32 /* number of bits of each program instruction when stored in the PROM memory (applied only when the user selects reporting in bytes) */\r\n", +"\r\n", +"#ifdef WMOPS\r\n", +"enum instructions\r\n", +"{\r\n", +" _ADD,\r\n", +" _ABS,\r\n", +" _MULT,\r\n", +" _MAC,\r\n", +" _MOVE,\r\n", +" _STORE,\r\n", +" _LOGIC,\r\n", +" _SHIFT,\r\n", +" _BRANCH,\r\n", +" _DIV,\r\n", +" _SQRT,\r\n", +" _TRANS,\r\n", +" _FUNC,\r\n", +" _LOOP,\r\n", +" _INDIRECT,\r\n", +" _PTR_INIT,\r\n", +" _TEST,\r\n", +" _POWER,\r\n", +" _LOG,\r\n", +" _MISC,\r\n", +" NUM_INST\r\n", +"};\r\n", +"\r\n", +"#define _ADD_C 1\r\n", +"#define _ABS_C 1\r\n", +"#define _MULT_C 1\r\n", +"#define _MAC_C 1\r\n", +"#define _MOVE_C 1\r\n", +"#define _STORE_C 1\r\n", +"#define _LOGIC_C 1\r\n", +"#define _SHIFT_C 1\r\n", +"#define _BRANCH_C 4\r\n", +"#define _DIV_C 18\r\n", +"#define _SQRT_C 10\r\n", +"#define _TRANS_C 25\r\n", +"#define _FUNC_C 2 /* need to add number of arguments */\r\n", +"#define _LOOP_C 3\r\n", +"#define _INDIRECT_C 2\r\n", +"#define _PTR_INIT_C 1\r\n", +"#define _TEST_C 2\r\n", +"#define _POWER_C 25\r\n", +"#define _LOG_C 25\r\n", +"#define _MISC_C 1\r\n", +"\r\n", +"#define _ADD_P 1\r\n", +"#define _ABS_P 1\r\n", +"#define _MULT_P 1\r\n", +"#define _MAC_P 1\r\n", +"#define _MOVE_P 1\r\n", +"#define _STORE_P 0\r\n", +"#define _LOGIC_P 1\r\n", +"#define _SHIFT_P 1\r\n", +"#define _BRANCH_P 2\r\n", +"#define _DIV_P 2\r\n", +"#define _SQRT_P 2\r\n", +"#define _TRANS_P 2\r\n", +"#define _FUNC_P 2 /* need to add number of arguments */\r\n", +"#define _LOOP_P 1\r\n", +"#define _INDIRECT_P 2\r\n", +"#define _PTR_INIT_P 1\r\n", +"#define _TEST_P 1\r\n", +"#define _POWER_P 2\r\n", +"#define _LOG_P 2\r\n", +"#define _MISC_P 1\r\n", +"\r\n", +"#define ADD( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _ADD_C * ( x ) ); \\\r\n", +" inst_cnt[_ADD] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _ADD_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define ABS( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _ABS_C * ( x ) ); \\\r\n", +" inst_cnt[_ABS] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _ABS_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define MULT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _MULT_C * ( x ) ); \\\r\n", +" inst_cnt[_MULT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MULT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define MAC( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _MAC_C * ( x ) ); \\\r\n", +" inst_cnt[_MAC] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MAC_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define MOVE( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _MOVE_C * ( x ) ); \\\r\n", +" inst_cnt[_MOVE] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MOVE_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define STORE( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _STORE_C * ( x ) ); \\\r\n", +" inst_cnt[_STORE] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _STORE_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define LOGIC( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _LOGIC_C * ( x ) ); \\\r\n", +" inst_cnt[_LOGIC] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _LOGIC_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define SHIFT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _SHIFT_C * ( x ) ); \\\r\n", +" inst_cnt[_SHIFT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _SHIFT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define BRANCH( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _BRANCH_C * ( x ) ); \\\r\n", +" inst_cnt[_BRANCH] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _BRANCH_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DIV( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _DIV_C * ( x ) ); \\\r\n", +" inst_cnt[_DIV] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _DIV_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define SQRT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _SQRT_C * ( x ) ); \\\r\n", +" inst_cnt[_SQRT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _SQRT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define TRANS( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _TRANS_C * ( x ) ); \\\r\n", +" inst_cnt[_TRANS] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _TRANS_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define LOOP( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _LOOP_C * ( x ) ); \\\r\n", +" inst_cnt[_LOOP] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _LOOP_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define INDIRECT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _INDIRECT_C * ( x ) ); \\\r\n", +" inst_cnt[_INDIRECT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _INDIRECT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define PTR_INIT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _PTR_INIT_C * ( x ) ); \\\r\n", +" inst_cnt[_PTR_INIT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _PTR_INIT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define TEST( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _TEST_C * ( x ) ); \\\r\n", +" inst_cnt[_TEST] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _TEST_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define POWER( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _POWER_C * ( x ) ); \\\r\n", +" inst_cnt[_POWER] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _POWER_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define LOG( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _LOG_C * ( x ) ); \\\r\n", +" inst_cnt[_LOG] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _LOG_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define MISC( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _MISC_C * ( x ) ); \\\r\n", +" inst_cnt[_MISC] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MISC_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"\r\n", +"#define FUNC( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( _FUNC_C + _MOVE_C * ( x ) ); \\\r\n", +" inst_cnt[_FUNC]++; \\\r\n", +" inst_cnt[_MOVE] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _FUNC_P + _MOVE_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"\r\n", +"#define DADD( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _ADD_C * ( x ) ); \\\r\n", +" inst_cnt[_ADD] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _ADD_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DMULT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _MULT_C * ( x ) ); \\\r\n", +" inst_cnt[_MULT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MULT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DMAC( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _MAC_C * ( x ) ); \\\r\n", +" inst_cnt[_MAC] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MAC_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DMOVE( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _MOVE_C * ( x ) ); \\\r\n", +" inst_cnt[_MOVE] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _MOVE_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DSTORE( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _STORE_C * ( x ) ); \\\r\n", +" inst_cnt[_STORE] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _STORE_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DLOGIC( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _LOGIC_C * ( x ) ); \\\r\n", +" inst_cnt[_LOGIC] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _LOGIC_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DSHIFT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _SHIFT_C * ( x ) ); \\\r\n", +" inst_cnt[_SHIFT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _SHIFT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DDIV( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _DIV_C * ( x ) ); \\\r\n", +" inst_cnt[_DIV] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _DIV_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DSQRT( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _SQRT_C * ( x ) ); \\\r\n", +" inst_cnt[_SQRT] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _SQRT_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"#define DTRANS( x ) \\\r\n", +" { \\\r\n", +" { \\\r\n", +" ops_cnt += ( 2 * _TRANS_C * ( x ) ); \\\r\n", +" inst_cnt[_TRANS] += ( x ); \\\r\n", +" { \\\r\n", +" static int pcnt; \\\r\n", +" if ( !pcnt ) \\\r\n", +" { \\\r\n", +" pcnt = 1; \\\r\n", +" prom_cnt += ( _TRANS_P * ( x ) ); \\\r\n", +" } \\\r\n", +" } \\\r\n", +" } \\\r\n", +" }\r\n", +"\r\n", +"extern double ops_cnt;\r\n", +"extern double prom_cnt;\r\n", +"extern double inst_cnt[NUM_INST];\r\n", +"\r\n", +"void reset_wmops( void );\r\n", +"void push_wmops( const char *label );\r\n", +"void pop_wmops( void );\r\n", +"void update_wmops( void );\r\n", +"void update_mem( void );\r\n", +"void print_wmops( void );\r\n", +"\r\n", +"#else /* WMOPS counting disabled */\r\n", +"\r\n", +"#define reset_wmops()\r\n", +"extern int cntr_push_pop;\r\n", +"#define push_wmops( x ) ( cntr_push_pop++ )\r\n", +"#define pop_wmops() ( cntr_push_pop-- )\r\n", +"#define update_wmops() ( assert( cntr_push_pop == 0 ) )\r\n", +"#define update_mem()\r\n", +"#define print_wmops()\r\n", +"\r\n", +"#define ADD( x )\r\n", +"#define ABS( x )\r\n", +"#define MULT( x )\r\n", +"#define MAC( x )\r\n", +"#define MOVE( x )\r\n", +"#define STORE( x )\r\n", +"#define LOGIC( x )\r\n", +"#define SHIFT( x )\r\n", +"#define BRANCH( x )\r\n", +"#define DIV( x )\r\n", +"#define SQRT( x )\r\n", +"#define TRANS( x )\r\n", +"#define FUNC( x )\r\n", +"#define LOOP( x )\r\n", +"#define INDIRECT( x )\r\n", +"#define PTR_INIT( x )\r\n", +"#define TEST( x )\r\n", +"#define POWER( x )\r\n", +"#define LOG( x )\r\n", +"#define MISC( x )\r\n", +"\r\n", +"#define DADD( x )\r\n", +"#define DMULT( x )\r\n", +"#define DMAC( x )\r\n", +"#define DMOVE( x )\r\n", +"#define DSTORE( x )\r\n", +"#define DLOGIC( x )\r\n", +"#define DSHIFT( x )\r\n", +"#define DDIV( x )\r\n", +"#define DSQRT( x )\r\n", +"#define DTRANS( x )\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"#ifndef WMOPS\r\n", +"/* DESACTIVATE the Counting Mechanism */\r\n", +"#define OP_COUNT_( op, n )\r\n", +"\r\n", +"/* DESACTIVATE Operation Counter Wrappers */\r\n", +"#define OP_COUNT_WRAPPER1_( op, val ) ( val )\r\n", +"#define OP_COUNT_WRAPPER2_( expr )\r\n", +"#define OP_COUNT_WRAPPER3_( op, expr ) expr\r\n", +"\r\n", +"/* DESACTIVATE Logical & Ternary Operators */\r\n", +"#define __\r\n", +"#define _\r\n", +"\r\n", +"#else\r\n", +"\r\n", +"/* '*ops_cnt_ptr' is Used to Avoid: \"warning: operation on 'ops_cnt' may be undefined\" with Cygwin gcc Compiler */\r\n", +"static double *ops_cnt_ptr = &ops_cnt;\r\n", +"#define OP_COUNT_( op, x ) ( *ops_cnt_ptr += ( op##_C * ( x ) ), inst_cnt[op] += ( x ) )\r\n", +"\r\n", +"/******************************************************************/\r\n", +"/* NOTES: */\r\n", +"/* The 'wmc_flag_' flag is global to avoid declaration in every */\r\n", +"/* function and 'static' to avoid clashing with other modules */\r\n", +"/* that include this header file. */\r\n", +"/* */\r\n", +"/* The declarations of 'wmc_flag_' and 'wops_' in this header */\r\n", +"/* file prevent the addition of a 'C' file to the Project. */\r\n", +"/******************************************************************/\r\n", +"\r\n", +"/* General Purpose Global Flag */\r\n", +"static int wmc_flag_ = 0;\r\n", +"\r\n", +"/* Operation Counter Wrappers */\r\n", +"#define OP_COUNT_WRAPPER1_( op, val ) ( op, val )\r\n", +"#define OP_COUNT_WRAPPER2_( expr ) \\\r\n", +" if ( expr, 0 ) \\\r\n", +" ; \\\r\n", +" else\r\n", +"#define OP_COUNT_WRAPPER3_( op, expr ) \\\r\n", +" if ( op, 0 ) \\\r\n", +" ; \\\r\n", +" else \\\r\n", +" expr\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"/* Define all Macros without '{' & '}' (None of these should be called externally!) */\r\n", +"#define ABS_( x ) OP_COUNT_( _ABS, ( x ) )\r\n", +"#define ADD_( x ) OP_COUNT_( _ADD, ( x ) )\r\n", +"#define MULT_( x ) OP_COUNT_( _MULT, ( x ) )\r\n", +"#define MAC_( x ) OP_COUNT_( _MAC, ( x ) )\r\n", +"#define MOVE_( x ) OP_COUNT_( _MOVE, ( x ) )\r\n", +"#define STORE_( x ) OP_COUNT_( _STORE, ( x ) )\r\n", +"#define LOGIC_( x ) OP_COUNT_( _LOGIC, ( x ) )\r\n", +"#define SHIFT_( x ) OP_COUNT_( _SHIFT, ( x ) )\r\n", +"#define BRANCH_( x ) OP_COUNT_( _BRANCH, ( x ) )\r\n", +"#define DIV_( x ) OP_COUNT_( _DIV, ( x ) )\r\n", +"#define SQRT_( x ) OP_COUNT_( _SQRT, ( x ) )\r\n", +"#define TRANS_( x ) OP_COUNT_( _TRANS, ( x ) )\r\n", +"#define POWER_( x ) TRANS_( x )\r\n", +"#define LOG_( x ) TRANS_( x )\r\n", +"#define LOOP_( x ) OP_COUNT_( _LOOP, ( x ) )\r\n", +"#define INDIRECT_( x ) OP_COUNT_( _INDIRECT, ( x ) )\r\n", +"#define PTR_INIT_( x ) OP_COUNT_( _PTR_INIT, ( x ) )\r\n", +"#define FUNC_( x ) ( OP_COUNT_( _MOVE, ( x ) ), OP_COUNT_( _FUNC, 1 ) )\r\n", +"#define MISC_( x ) ABS_( x )\r\n", +"\r\n", +"/* Math Operations */\r\n", +"#define abs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), abs )\r\n", +"#define fabs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), fabs )\r\n", +"#define fabsf_ OP_COUNT_WRAPPER1_( ABS_( 1 ), fabsf )\r\n", +"#define labs_ OP_COUNT_WRAPPER1_( ABS_( 1 ), labs )\r\n", +"#define floor_ OP_COUNT_WRAPPER1_( MISC_( 1 ), floor )\r\n", +"#define floorf_ OP_COUNT_WRAPPER1_( MISC_( 1 ), floorf )\r\n", +"#define sqrt_ OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrt )\r\n", +"#define sqrtf_ OP_COUNT_WRAPPER1_( SQRT_( 1 ), sqrtf )\r\n", +"#define pow_ OP_COUNT_WRAPPER1_( POWER_( 1 ), pow )\r\n", +"#define powf_ OP_COUNT_WRAPPER1_( POWER_( 1 ), powf )\r\n", +"#define exp_ OP_COUNT_WRAPPER1_( POWER_( 1 ), exp )\r\n", +"#define expf_ OP_COUNT_WRAPPER1_( POWER_( 1 ), expf )\r\n", +"#define log_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log )\r\n", +"#define logf_ OP_COUNT_WRAPPER1_( LOG_( 1 ), logf )\r\n", +"#define log10_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log10 )\r\n", +"#define log10f_ OP_COUNT_WRAPPER1_( LOG_( 1 ), log10f )\r\n", +"#define cos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cos )\r\n", +"#define cosf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cosf )\r\n", +"#define sin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sin )\r\n", +"#define sinf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinf )\r\n", +"#define tan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tan )\r\n", +"#define tanf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanf )\r\n", +"#define acos_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), acos )\r\n", +"#define acosf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), acosf )\r\n", +"#define asin_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), asin )\r\n", +"#define asinf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), asinf )\r\n", +"#define atan_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan )\r\n", +"#define atanf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atanf )\r\n", +"#define atan2_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan2 )\r\n", +"#define atan2f_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), atan2f )\r\n", +"#define cosh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), cosh )\r\n", +"#define coshf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), coshf )\r\n", +"#define sinh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinh )\r\n", +"#define sinhf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), sinhf )\r\n", +"#define tanh_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanh )\r\n", +"#define tanhf_ OP_COUNT_WRAPPER1_( TRANS_( 1 ), tanhf )\r\n", +"#define fmod_ OP_COUNT_WRAPPER1_( DIV_( 1 ), fmod )\r\n", +"#define fmodf_ OP_COUNT_WRAPPER1_( DIV_( 1 ), fmodf )\r\n", +"#define frexp_ OP_COUNT_WRAPPER1_( MISC_( 2 ), frexp )\r\n", +"#define frexpf_ OP_COUNT_WRAPPER1_( MISC_( 2 ), frexpf )\r\n", +"\r\n", +"/* the macros below are instrumented versions of user-defined macros that might be used in the source code \r\n", +"/* representing some well-known and recognized mathematical operations (that are not defined in math.h) */\r\n", +"/* Note: the 'wmc_flag_=wmc_flag_' is used to avoid warning: left-hand operand of comma expression has no effect with gcc */\r\n", +"\r\n", +"#define min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), min( ( a ), ( b ) ) )\r\n", +"#define max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), max( ( a ), ( b ) ) )\r\n", +"#define MIN_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MIN( ( a ), ( b ) ) )\r\n", +"#define MAX_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), MAX( ( a ), ( b ) ) )\r\n", +"#define Min_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Min( ( a ), ( b ) ) )\r\n", +"#define Max_( a, b ) OP_COUNT_WRAPPER1_( MISC_( 1 ), Max( ( a ), ( b ) ) )\r\n", +"#define sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), sqr( ( x ) ) )\r\n", +"#define Sqr_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Sqr( ( x ) ) )\r\n", +"#define SQR_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQR( ( x ) ) )\r\n", +"#define square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), square( ( x ) ) )\r\n", +"#define Square_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), Square( ( x ) ) )\r\n", +"#define SQUARE_( x ) OP_COUNT_WRAPPER1_( MULT_( 1 ), SQUARE( ( x ) ) )\r\n", +"#define sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), sign( ( x ) ) )\r\n", +"#define Sign_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), Sign( ( x ) ) )\r\n", +"#define SIGN_( x ) OP_COUNT_WRAPPER1_( MOVE_( 1 ), SIGN( ( x ) ) )\r\n", +"#define inv_sqrt_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), inv_sqrt( ( x ) ) )\r\n", +"#define inv_sqrtf_( x ) OP_COUNT_WRAPPER1_( SQRT_( 1 ), inv_sqrtf( ( x ) ) )\r\n", +"#define log_base_2_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log_base_2( ( x ) ) )\r\n", +"#define log2_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2( ( x ) ) )\r\n", +"#define log2f_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2f( ( x ) ) )\r\n", +"#define log2_f_( x ) OP_COUNT_WRAPPER1_( ( LOG_( 1 ), MULT_( 1 ) ), log2_f( ( x ) ) )\r\n", +"#define _round_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, _round( ( x ) ) )\r\n", +"#define round_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, round( ( x ) ) )\r\n", +"#define round_f_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, round_f( ( x ) ) )\r\n", +"#define roundf_( x ) OP_COUNT_WRAPPER1_( wmc_flag_ = wmc_flag_, roundf( ( x ) ) )\r\n", +"#define set_min_( a, b ) OP_COUNT_WRAPPER3_( ( ADD_( 1 ), BRANCH_( 1 ), MOVE_( 1 ) ), set_min( ( a ), ( b ) ) )\r\n", +"#define set_max_( a, b ) OP_COUNT_WRAPPER3_( ( ADD_( 1 ), BRANCH_( 1 ), MOVE_( 1 ) ), set_max( ( a ), ( b ) ) )\r\n", +"\r\n", +"/* Functions */\r\n", +"#define func_( name, x ) OP_COUNT_WRAPPER1_( FUNC_( x ), name )\r\n", +"\r\n", +"/* Logical Operators */\r\n", +"#ifndef __\r\n", +"#define __ ( BRANCH_( 1 ), 1 ) &&\r\n", +"#endif\r\n", +"\r\n", +"/* Ternary Operators (? and :) */\r\n", +"#ifndef _\r\n", +"#define _ ( BRANCH_( 1 ), 0 ) ? 0:\r\n", +"#endif\r\n", +"\r\n", +"/* Flow Control keywords */\r\n", +"#define if_ \\\r\n", +" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n", +" if\r\n", +"#define for_ OP_COUNT_WRAPPER2_( LOOP_(1)) for\r\n", +"#define while_( c ) \\\r\n", +" while \\\r\n", +" OP_COUNT_WRAPPER1_( BRANCH_( 1 ), ( c ) ) /* needs extra \"()\" if ',' encountered */\r\n", +"#define do_ \\\r\n", +" do \\\r\n", +" {\r\n", +"#define _while \\\r\n", +" BRANCH_( 1 ); \\\r\n", +" } \\\r\n", +" while\r\n", +"\r\n", +"#define goto_ \\\r\n", +" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n", +" goto\r\n", +"#define break_ \\\r\n", +" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n", +" break\r\n", +"#define continue_ \\\r\n", +" OP_COUNT_WRAPPER2_( BRANCH_( 1 ) ) \\\r\n", +" continue\r\n", +"#define return_ \\\r\n", +" OP_COUNT_WRAPPER2_( ( wmc_flag_ = stack_tree_level_, STACK_DEPTH_FCT_RETURN ) ) \\\r\n", +" return\r\n", +"\r\n", +"#define switch_ \\\r\n", +" OP_COUNT_WRAPPER2_( ( BRANCH_( 1 ), wmc_flag_ = 1 ) ) \\\r\n", +" switch\r\n", +"#define cost_( n ) OP_COUNT_WRAPPER2_( wmc_flag_ ? ( ADD_( n ), BRANCH_( n ), wmc_flag_ = 0 ) : 0 );\r\n", +"\r\n", +"#ifdef WMOPS\r\n", +"\r\n", +"#define ACC 2\r\n", +"#define MUL 1\r\n", +"\r\n", +"/* Counting Function (should not be called externally!) */\r\n", +"static void wops_( const char *ops )\r\n", +"{\r\n", +" char lm = 0; /* lm: Last Operation is Math */\r\n", +" static char lo = 0; /* Last Operation */\r\n", +"\r\n", +" void ( *fct )( const char *ops ) = wops_;\r\n", +"\r\n", +"st:\r\n", +" while ( *ops != '\\0' )\r\n", +" {\r\n", +" switch ( *ops++ )\r\n", +" {\r\n", +" int cnt;\r\n", +" case '-':\r\n", +" for ( cnt = 0; ops[cnt] == '>'; cnt++ )\r\n", +" ;\r\n", +" if ( cnt & 1 )\r\n", +" goto ind;\r\n", +" case '+':\r\n", +" lm = 2;\r\n", +" if ( lo & MUL )\r\n", +" {\r\n", +" MULT_( -1 );\r\n", +" MAC_( 1 );\r\n", +" break;\r\n", +" }\r\n", +" lo = ACC << 2;\r\n", +" case 'U':\r\n", +" case 'D':\r\n", +" ADD_( 1 );\r\n", +" break;\r\n", +" case '*':\r\n", +" lm = 2;\r\n", +" if ( lo & ACC )\r\n", +" {\r\n", +" ADD_( -1 );\r\n", +" MAC_( 1 );\r\n", +" break;\r\n", +" }\r\n", +" lo = MUL << 2;\r\n", +" MULT_( 1 );\r\n", +" break;\r\n", +" case '/':\r\n", +" case '%':\r\n", +" lm = 2;\r\n", +" DIV_( 1 );\r\n", +" break;\r\n", +" case '&':\r\n", +" case '|':\r\n", +" case '^':\r\n", +" lm = 2;\r\n", +" case '~':\r\n", +" LOGIC_( 1 );\r\n", +" break;\r\n", +" case '<':\r\n", +" case '>':\r\n", +" if ( *ops != ops[-1] )\r\n", +" goto error;\r\n", +" ops++;\r\n", +" case -85:\r\n", +" case -69:\r\n", +" lm = 2;\r\n", +" SHIFT_( 1 );\r\n", +" break;\r\n", +" case 'L':\r\n", +" case 'G':\r\n", +" if ( *ops == 't' )\r\n", +" goto comp;\r\n", +" case 'E':\r\n", +" case 'N':\r\n", +" if ( *ops != 'e' )\r\n", +" goto error;\r\n", +" comp:\r\n", +" ops++;\r\n", +" ADD_( 1 );\r\n", +" break;\r\n", +" case '!':\r\n", +" MISC_( 2 );\r\n", +" break;\r\n", +" case 'M':\r\n", +" MOVE_( 1 );\r\n", +" break;\r\n", +" case 'S':\r\n", +" STORE_( 1 );\r\n", +" break;\r\n", +" case 'P':\r\n", +" PTR_INIT_( 1 );\r\n", +" break;\r\n", +" case '[':\r\n", +" case ']':\r\n", +" goto st;\r\n", +" ind:\r\n", +" ops++;\r\n", +" case 'I':\r\n", +" case '.':\r\n", +" INDIRECT_( 1 );\r\n", +" break;\r\n", +" case '=':\r\n", +" if ( lm )\r\n", +" goto st;\r\n", +" case '\\0':\r\n", +" /* This Shouldn't Happen */\r\n", +" /* These are Used to Avoid: \"warning: 'name' defined but not used\" with Cygwin gcc Compiler */\r\n", +" wmc_flag_ = wmc_flag_;\r\n", +" ops_cnt_ptr = ops_cnt_ptr;\r\n", +" fct( \"\" );\r\n", +" error:\r\n", +" default:\r\n", +" fprintf( stderr, \"\\r wops: Invalid Counting Operation '%s'\\n\", ops - 1 );\r\n", +" exit( -1 );\r\n", +" }\r\n", +" lm >>= 1;\r\n", +" lo >>= 2;\r\n", +" }\r\n", +"\r\n", +" return;\r\n", +"}\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"/* All Other Operations */\r\n", +"#define $( str ) OP_COUNT_WRAPPER2_( wops_( str ) )\r\n", +"\r\n", +"\r\n", +"/*-------------------------------------------------------------------*\r\n", +" * Memory counting tool\r\n", +" *-------------------------------------------------------------------*/\r\n", +"\r\n", +"/* Enhanced Const Data Size Counting (Rounding Up to the Nearest 'Integer' Size) */\r\n", +"#define rsize( item ) ( ( sizeof( item ) + sizeof( int ) - 1 ) / sizeof( int ) * sizeof( int ) )\r\n", +"\r\n", +"#ifdef _MSC_VER\r\n", +"/* Disable \"warning C4210: nonstandard extension used : function given file scope\" with Visual Studio Compiler */\r\n", +"#pragma warning( disable : 4210 )\r\n", +"#endif\r\n", +"\r\n", +"/* Const Data Size and PROM Size Wrapper Functions */\r\n", +"#define Const_Data_Size_Func( file ) Const_Data_Size_##file( void )\r\n", +"#define Get_Const_Data_Size( file, val_ptr ) \\\r\n", +" { \\\r\n", +" extern int Const_Data_Size_##file( void ); \\\r\n", +" *( val_ptr ) = Const_Data_Size_##file(); \\\r\n", +" }\r\n", +"#define PROM_Size_Func( file ) PROM_Size_##file( void )\r\n", +"#define Get_PROM_Size( file, val_ptr ) \\\r\n", +" { \\\r\n", +" int PROM_Size_##file( void ); \\\r\n", +" *( val_ptr ) = PROM_Size_##file(); \\\r\n", +" }\r\n", +"\r\n", +"/* ROM Size Lookup Table - contains information about PROM size and Const Data Size in all source files */\r\n", +"/* The print_mem() function looks for this table to print the results of Const Data usage and PROM usage */\r\n", +"typedef struct ROM_Size_Lookup_Table\r\n", +"{\r\n", +" const char file_spec[255];\r\n", +" int PROM_size;\r\n", +" int ( *Get_Const_Data_Size_Func )( void );\r\n", +"} ROM_Size_Lookup_Table;\r\n", +"\r\n", +"/* The WMC tool inserts the following declaration during the innstrumentation process in the .c file where the function print_mem() is located */\r\n", +"/* and modifies it to print_mem(Const_Data_PROM_Table) */\r\n", +"\r\n", +"/* #ifdef WMOPS\r\n", +" * ROM_Size_Lookup_Table Const_Data_PROM_Table[] =\r\n", +" * {\r\n", +" * {\"../lib_enc/rom_enc.c\", 0, NULL},\r\n", +" * {\"../lib_com/*.c\", 0, NULL},\r\n", +" * {\"\", -1, NULL}\r\n", +" * };\r\n", +" * #endif\r\n", +" */\r\n", +"\r\n", +"/*#define MEM_ALIGN_64BITS */ /* Define this when using 64 Bits values in the code (ex: double), otherwise it will align on 32 Bits */\r\n", +"/*#define MEM_COUNT_DETAILS*/\r\n", +"\r\n", +"typedef enum\r\n", +"{\r\n", +" USE_BYTES = 0,\r\n", +" USE_16BITS = 1,\r\n", +" USE_32BITS = 2,\r\n", +" USE_64BITS = 3\r\n", +"} Counting_Size;\r\n", +"\r\n", +"#if ( defined( _WIN32 ) && ( _MSC_VER <= 1800 ) && ( _MSC_VER >= 1300 ) )\r\n", +"#define __func__ __FUNCTION__\r\n", +"#elif defined( __STDC_VERSION__ ) && __STDC_VERSION__ < 199901L\r\n", +"#if ( __GNUC__ >= 2 )\r\n", +"#define __func__ __FUNCTION__\r\n", +"#else\r\n", +"#define __func__ \"\"\r\n", +"#endif\r\n", +"#elif defined( __GNUC__ )\r\n", +"#define __func__ __extension__ __FUNCTION__\r\n", +"#endif\r\n", +"\r\n", +"\r\n", +"#ifdef WMOPS\r\n", +"\r\n", +"void *mem_alloc( const char *func_name, int func_lineno, size_t size, char *alloc_str );\r\n", +"void mem_free( const char *func_name, int func_lineno, void *ptr );\r\n", +"\r\n", +"#define malloc_( size ) mem_alloc( __func__, __LINE__, size, \"m:\" #size )\r\n", +"#define calloc_( n, size ) mem_alloc( __func__, __LINE__, ( n ) * ( size ), \"c:\" #n \", \" #size )\r\n", +"#define free_( ptr ) mem_free( __func__, __LINE__, ptr )\r\n", +"\r\n", +"void reset_mem( Counting_Size cnt_size );\r\n", +"void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] );\r\n", +"\r\n", +"int push_stack( const char *filename, const char *fctname );\r\n", +"int pop_stack( const char *filename, const char *fctname );\r\n", +"\r\n", +"#ifdef WMOPS_DETAIL\r\n", +"#define STACK_DEPTH_FCT_CALL ( push_wmops( __FUNCTION__ \" [WMC_AUTO]\" ), push_stack( __FILE__, __FUNCTION__ ) ) /* add push_wmops() in all function calls */\r\n", +"#define STACK_DEPTH_FCT_RETURN ( pop_wmops(), pop_stack( __FILE__, __FUNCTION__ ) ) /* add pop_wmops() in all function returns */\r\n", +"#else\r\n", +"#define STACK_DEPTH_FCT_CALL push_stack( __FILE__, __FUNCTION__ )\r\n", +"#define STACK_DEPTH_FCT_RETURN pop_stack( __FILE__, __FUNCTION__ )\r\n", +"#endif\r\n", +"\r\n", +"void reset_stack( void );\r\n", +"#define func_start_ int stack_tree_level_ = STACK_DEPTH_FCT_CALL;\r\n", +"\r\n", +"#else\r\n", +"#define malloc_( n1 ) malloc( n1 )\r\n", +"#define calloc_( n1, n2 ) calloc( n1, n2 )\r\n", +"#define free_( ptr ) free( ptr )\r\n", +"#define reset_mem( cnt_size )\r\n", +"#define print_mem( Const_Data_PROM_Table )\r\n", +"\r\n", +"#define push_stack( file, fct )\r\n", +"#define pop_stack( file, fct )\r\n", +"#define reset_stack()\r\n", +"#define func_start_\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"\r\n", +"/* Global counter variable for calculation of complexity weight */\r\n", +"typedef struct\r\n", +"{\r\n", +" unsigned int add; /* Complexity Weight of 1 */\r\n", +" unsigned int sub; /* Complexity Weight of 1 */\r\n", +" unsigned int abs_s; /* Complexity Weight of 1 */\r\n", +" unsigned int shl; /* Complexity Weight of 1 */\r\n", +" unsigned int shr; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int extract_h; /* Complexity Weight of 1 */\r\n", +" unsigned int extract_l; /* Complexity Weight of 1 */\r\n", +" unsigned int mult; /* Complexity Weight of 1 */\r\n", +" unsigned int L_mult; /* Complexity Weight of 1 */\r\n", +" unsigned int negate; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int round; /* Complexity Weight of 1 */\r\n", +" unsigned int L_mac; /* Complexity Weight of 1 */\r\n", +" unsigned int L_msu; /* Complexity Weight of 1 */\r\n", +" unsigned int L_macNs; /* Complexity Weight of 1 */\r\n", +" unsigned int L_msuNs; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L_add; /* Complexity Weight of 1 */\r\n", +" unsigned int L_sub; /* Complexity Weight of 1 */\r\n", +" unsigned int L_add_c; /* Complexity Weight of 2 */\r\n", +" unsigned int L_sub_c; /* Complexity Weight of 2 */\r\n", +" unsigned int L_negate; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L_shl; /* Complexity Weight of 1 */\r\n", +" unsigned int L_shr; /* Complexity Weight of 1 */\r\n", +" unsigned int mult_r; /* Complexity Weight of 1 */\r\n", +" unsigned int shr_r; /* Complexity Weight of 3 */\r\n", +" unsigned int mac_r; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int msu_r; /* Complexity Weight of 1 */\r\n", +" unsigned int L_deposit_h; /* Complexity Weight of 1 */\r\n", +" unsigned int L_deposit_l; /* Complexity Weight of 1 */\r\n", +" unsigned int L_shr_r; /* Complexity Weight of 3 */\r\n", +" unsigned int L_abs; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L_sat; /* Complexity Weight of 4 */\r\n", +" unsigned int norm_s; /* Complexity Weight of 1 */\r\n", +" unsigned int div_s; /* Complexity Weight of 18 */\r\n", +" unsigned int norm_l; /* Complexity Weight of 1 */\r\n", +" unsigned int move16; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int move32; /* Complexity Weight of 2 */\r\n", +" unsigned int Logic16; /* Complexity Weight of 1 */\r\n", +" unsigned int Logic32; /* Complexity Weight of 2 */\r\n", +" unsigned int Test; /* Complexity Weight of 2 */\r\n", +" unsigned int s_max; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int s_min; /* Complexity Weight of 1 */\r\n", +" unsigned int L_max; /* Complexity Weight of 1 */\r\n", +" unsigned int L_min; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_max; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_min; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int shl_r; /* Complexity Weight of 3 */\r\n", +" unsigned int L_shl_r; /* Complexity Weight of 3 */\r\n", +" unsigned int L40_shr_r; /* Complexity Weight of 3 */\r\n", +" unsigned int L40_shl_r; /* Complexity Weight of 3 */\r\n", +" unsigned int norm_L40; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L40_shl; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_shr; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_negate; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_add; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_sub; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L40_abs; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_mult; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_mac; /* Complexity Weight of 1 */\r\n", +" unsigned int mac_r40; /* Complexity Weight of 2 */\r\n", +"\r\n", +" unsigned int L40_msu; /* Complexity Weight of 1 */\r\n", +" unsigned int msu_r40; /* Complexity Weight of 2 */\r\n", +" unsigned int Mpy_32_16_ss; /* Complexity Weight of 2 */\r\n", +" unsigned int Mpy_32_32_ss; /* Complexity Weight of 4 */\r\n", +" unsigned int L_mult0; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L_mac0; /* Complexity Weight of 1 */\r\n", +" unsigned int L_msu0; /* Complexity Weight of 1 */\r\n", +" unsigned int lshl; /* Complexity Weight of 1 */\r\n", +" unsigned int lshr; /* Complexity Weight of 1 */\r\n", +" unsigned int L_lshl; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L_lshr; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_lshl; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_lshr; /* Complexity Weight of 1 */\r\n", +" unsigned int s_and; /* Complexity Weight of 1 */\r\n", +" unsigned int s_or; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int s_xor; /* Complexity Weight of 1 */\r\n", +" unsigned int L_and; /* Complexity Weight of 1 */\r\n", +" unsigned int L_or; /* Complexity Weight of 1 */\r\n", +" unsigned int L_xor; /* Complexity Weight of 1 */\r\n", +" unsigned int rotl; /* Complexity Weight of 3 */\r\n", +"\r\n", +" unsigned int rotr; /* Complexity Weight of 3 */\r\n", +" unsigned int L_rotl; /* Complexity Weight of 3 */\r\n", +" unsigned int L_rotr; /* Complexity Weight of 3 */\r\n", +" unsigned int L40_set; /* Complexity Weight of 3 */\r\n", +" unsigned int L40_deposit_h; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L40_deposit_l; /* Complexity Weight of 1 */\r\n", +" unsigned int L40_deposit32; /* Complexity Weight of 1 */\r\n", +" unsigned int Extract40_H; /* Complexity Weight of 1 */\r\n", +" unsigned int Extract40_L; /* Complexity Weight of 1 */\r\n", +" unsigned int L_Extract40; /* Complexity Weight of 1 */\r\n", +"\r\n", +" unsigned int L40_round; /* Complexity Weight of 1 */\r\n", +" unsigned int L_saturate40; /* Complexity Weight of 1 */\r\n", +" unsigned int round40; /* Complexity Weight of 1 */\r\n", +" unsigned int If; /* Complexity Weight of 4 */\r\n", +" unsigned int Goto; /* Complexity Weight of 4 */\r\n", +"\r\n", +" unsigned int Break; /* Complexity Weight of 4 */\r\n", +" unsigned int Switch; /* Complexity Weight of 8 */\r\n", +" unsigned int For; /* Complexity Weight of 3 */\r\n", +" unsigned int While; /* Complexity Weight of 4 */\r\n", +" unsigned int Continue; /* Complexity Weight of 4 */\r\n", +"\r\n", +" unsigned int L_mls; /* Complexity Weight of 6 */\r\n", +" unsigned int div_l; /* Complexity Weight of 32 */\r\n", +" unsigned int i_mult; /* Complexity Weight of 3 */\r\n", +"} BASIC_OP;\r\n", +"\r\n", +"#ifdef WMOPS\r\n", +"extern BASIC_OP *multiCounter;\r\n", +"extern int currCounter;\r\n", +"\r\n", +"/* Technical note :\r\n", +" * The following 3 variables are only used for correct complexity\r\n", +" * evaluation of the following structure :\r\n", +" * IF{\r\n", +" * ...\r\n", +" * } ELSE IF {\r\n", +" * ...\r\n", +" * } ELSE IF {\r\n", +" * ...\r\n", +" * }\r\n", +" * ...\r\n", +" * } ELSE {\r\n", +" * ...\r\n", +" * }\r\n", +" */\r\n", +"extern int funcId_where_last_call_to_else_occurred;\r\n", +"extern long funcid_total_wmops_at_last_call_to_else;\r\n", +"extern int call_occurred;\r\n", +"\r\n", +"extern long TotalWeightedOperation( void );\r\n", +"long DeltaWeightedOperation( void );\r\n", +"\r\n", +"void Set_BASOP_WMOPS_counter( int counterId );\r\n", +"void Reset_BASOP_WMOPS_counter( void );\r\n", +"\r\n", +"#endif\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : FOR\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro FOR should be used instead of the 'for' C statement.\r\n", +" * The complexity is independent of the number of loop iterations that are\r\n", +" * performed.\r\n", +" *\r\n", +" * Complexity weight : 3 (regardless of number of iterations).\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define FOR( a) for( a)\r\n", +"\r\n", +"#else \r\n", +"#define FOR( a) if( incrFor(), 0); else for( a)\r\n", +"\r\n", +"static __inline void incrFor( void) {\r\n", +" multiCounter[currCounter].For++;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : WHILE\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro WHILE should be used instead of the 'while' C statement.\r\n", +" * The complexity is proportional to the number of loop iterations that\r\n", +" * are performed.\r\n", +" *\r\n", +" * Complexity weight : 4 x 'number of loop iterations'.\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define WHILE( a) while( a)\r\n", +"\r\n", +"#else \r\n", +"#define WHILE( a) while( incrWhile(), a)\r\n", +"\r\n", +"static __inline void incrWhile( void) {\r\n", +" multiCounter[currCounter].While++;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : DO\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro DO should be used instead of the 'do' C statement.\r\n", +" *\r\n", +" * Complexity weight : 0 (complexity counted by WHILE macro).\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define DO do\r\n", +"\r\n", +"#else \r\n", +"#define DO do\r\n", +"\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : IF\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro IF should :\r\n", +" *\r\n", +" * - not be used when :\r\n", +" * - the 'if' structure does not have any 'else if' nor 'else' statement\r\n", +" * - and it conditions only one DSP basic operations.\r\n", +" *\r\n", +" * - be used instead of the 'if' C statement in every other case :\r\n", +" * - when there is an 'else' or 'else if' statement,\r\n", +" * - or when the 'if' conditions several DSP basic operations,\r\n", +" * - or when the 'if' conditions a function call.\r\n", +" *\r\n", +" * Complexity weight : 4\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define IF( a) if( a)\r\n", +"\r\n", +"#else \r\n", +"#define IF( a) if( incrIf(), a)\r\n", +"\r\n", +"static __inline void incrIf( void) {\r\n", +" /* Technical note :\r\n", +" * If the \"IF\" operator comes just after an \"ELSE\", its counter\r\n", +" * must not be incremented.\r\n", +" */\r\n", +" if ( ( currCounter != funcId_where_last_call_to_else_occurred ) || ( TotalWeightedOperation() != funcid_total_wmops_at_last_call_to_else ) || ( call_occurred == 1 ) )\r\n", +" {\r\n", +" multiCounter[currCounter].If++;\r\n", +" }\r\n", +"\r\n", +" call_occurred = 0;\r\n", +" funcId_where_last_call_to_else_occurred = INT_MAX;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : ELSE\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro ELSE should be used instead of the 'else' C statement.\r\n", +" *\r\n", +" * Complexity weight : 4\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define ELSE else\r\n", +"\r\n", +"#else \r\n", +"#define ELSE else if( incrElse(), 0) ; else\r\n", +"\r\n", +"static __inline void incrElse( void) {\r\n", +" multiCounter[currCounter].If++;\r\n", +"\r\n", +" /* We keep track of the funcId of the last function\r\n", +" * which used ELSE {...} structure.\r\n", +" */\r\n", +" funcId_where_last_call_to_else_occurred = currCounter;\r\n", +"\r\n", +" /* We keep track of the number of WMOPS of this funcId\r\n", +" * when the ELSE macro was called.\r\n", +" */\r\n", +" funcid_total_wmops_at_last_call_to_else = TotalWeightedOperation();\r\n", +"\r\n", +" /* call_occurred is set to 0, in order to count the next IF (if necessary)\r\n", +" */\r\n", +" call_occurred = 0;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : SWITCH\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro SWITCH should be used instead of the 'switch' C statement.\r\n", +" *\r\n", +" * Complexity weight : 8\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define SWITCH( a) switch( a)\r\n", +"\r\n", +"#else \r\n", +"#define SWITCH( a) switch( incrSwitch(), a)\r\n", +"\r\n", +"static __inline void incrSwitch( void) {\r\n", +" multiCounter[currCounter].Switch++;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : CONTINUE\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro CONTINUE should be used instead of the 'continue' C statement.\r\n", +" *\r\n", +" * Complexity weight : 4\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define CONTINUE continue\r\n", +"\r\n", +"#else \r\n", +"#define CONTINUE if( incrContinue(), 0); else continue\r\n", +"\r\n", +"static __inline void incrContinue( void) {\r\n", +" multiCounter[currCounter].Continue++;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : BREAK\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro BREAK should be used instead of the 'break' C statement.\r\n", +" *\r\n", +" * Complexity weight : 4\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define BREAK break\r\n", +"\r\n", +"#else \r\n", +"#define BREAK if( incrBreak(), 0) break; else break\r\n", +"\r\n", +"static __inline void incrBreak( void) {\r\n", +" multiCounter[currCounter].Break++;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"\r\n", +"/*****************************************************************************\r\n", +" *\r\n", +" * Function Name : GOTO\r\n", +" *\r\n", +" * Purpose :\r\n", +" *\r\n", +" * The macro GOTO should be used instead of the 'goto' C statement.\r\n", +" *\r\n", +" * Complexity weight : 4\r\n", +" *\r\n", +" *****************************************************************************/\r\n", +"#ifndef WMOPS\r\n", +"#define GOTO goto\r\n", +"\r\n", +"#else \r\n", +"#define GOTO if( incrGoto(), 0); else goto\r\n", +"\r\n", +"static __inline void incrGoto( void) {\r\n", +" multiCounter[currCounter].Goto++;\r\n", +"}\r\n", +"#endif \r\n", +"\r\n", +"#endif /* WMOPS_H */\r\n", +"\r\n", +"\r\n", +"\r\n", \ No newline at end of file diff --git a/src/wmc_tool/wmc_tool.cpp b/src/wmc_tool/wmc_tool.cpp index fd10202..dac4c48 100644 --- a/src/wmc_tool/wmc_tool.cpp +++ b/src/wmc_tool/wmc_tool.cpp @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -69,10 +69,10 @@ static void usage() { - Print("Usage: wmc_tool [options] filename1 filename2 ...\n\n" - "WMC tool v%s - %s\n\n" + Print("WMC tool v%s - %s\n\n" + "Usage: wmc_tool [options] filename1 filename2 ...\n\n" "Mandatory arguments:\n" - " space-separated list of filenames or directories with file mask, e.g. ./lib_enc/array*.c\n" + " space-separated list of filenames or directories with file mask, e.g. ./lib_enc/array*.c my_dir/sub_dir/*.c\n" " note: if file mask is not specified *.c is assumed by default\n\n" "Options:\n" " -h [--help]: print help\n" @@ -82,7 +82,8 @@ static void usage() " -m filename [--rom filename]: add statistics about ROM and RAM consumption\n" " note: filename shall point to a .c file containing the print_mem() function\n" " -b [--no-backup]: no backup of original files\n" - " -c dirname [--generate-wmc-files dirname]: copy wmc_auto.h and wmc_auto.c to a user-specified directory\n\n", + " -c dirname [--generate-wmc-files dirname]: copy wmc_auto.h and wmc_auto.c to a user-specified directory\n" + " -f value [--frames-per-second value]: set the number of frames per second (default 50.0)\n\n", WMC_TOOL_VERSION_NO, VERSION_STL); return; @@ -95,7 +96,8 @@ static TOOL_ERROR Parse_Command_Line( int* Operation, unsigned int* Tool_Warning_Mask, char* Const_Data_PROM_File, - char* wmops_output_dir + char* wmops_output_dir, + float *frames_per_sec ) { int i; @@ -126,6 +128,8 @@ static TOOL_ERROR Parse_Command_Line( /* Parse all options */ *i_last_cmd__line_option = 0; + *frames_per_sec = 50.0; + i = 0; while (i < nargs && *args[i] == '-') { @@ -221,12 +225,24 @@ static TOOL_ERROR Parse_Command_Line( *Operation |= OUTPUT_WMOPS_FILES; } + else if (_stricmp(arg_name, "f") == 0 || _stricmp(arg_name, "frames-per-second") == 0) + { + /* get the next argument - must be a positive float number */ + i++; + + /* get the value */ + if ((*frames_per_sec = strtof(args[i], NULL)) <= 0.0 ) + { + fprintf(stderr, "Incorrect number of frames per second specified: %s!\n\n", args[i]); + return ERR_CMD_LINE; + } + } /* Move to the next argument */ i++; } - /* return the position of the first non-option argument */ + /* return the position of the first non-optional argument */ *i_last_cmd__line_option = i; return NO_ERR; @@ -1008,75 +1024,116 @@ static TOOL_ERROR Process_File( * Output_Wmops_File *-------------------------------------------------------------------*/ -static TOOL_ERROR Output_Wmops_File( char *PathName, bool Backup ) +static TOOL_ERROR Output_Wmops_File( char *PathName, float frames_per_sec, bool Backup ) { TOOL_ERROR ErrCode = NO_ERR; - FILE *file; - int i; - size_t file_size; - char LongFileName[MAX_PATH + 1]; /* +1 for NUL Char*/ - - static const char wmops_auto_file_h[] = -#include "wmc_auto_h.txt" - ; - static const char wmops_auto_file_c[] = -#include "wmc_auto_c.txt" - ; + FILE *TargetFile; + int i, j, len, num_strings, offset; + char SrcFileName[MAX_PATH + 1]; /* +1 for NUL Char*/ + char TargetFileName[MAX_PATH + 1]; /* +1 for NUL Char*/ + char *text = NULL, temp_str[50]; + + const char* wmops_auto_files[] = { "wmc_auto.h", "wmc_auto.c" }; + const char** wmops_auto_file; + const char* wmops_auto_file_h[] = { + #include "wmc_auto_h.txt" + }; + const char* wmops_auto_file_c[] = { + #include "wmc_auto_c.txt" + }; + for (i = 0; i < 2; i++) { + /* get the pointer */ if (i == 0) { - /* Create Output Filename */ - strcpy(LongFileName, PathName); - strcat(LongFileName, "/wmc_auto.h"); + wmops_auto_file = wmops_auto_file_h; + num_strings = sizeof(wmops_auto_file_h) / sizeof(char*); + } + else + { + wmops_auto_file = wmops_auto_file_c; + num_strings = sizeof(wmops_auto_file_c) / sizeof(char*); + } + + /* calculate the total length required */ + len = 0; + for (j = 0; j < num_strings; j++) + { + len += (int) strlen(wmops_auto_file[j]); + } + len++; - /* Try opening the target file wmc_auto.h */ - if ((file = fopen(LongFileName, "wb")) == NULL) + /* allocate a char * buffer for further manipulation of the source file text */ + text = (char*) calloc(len, sizeof(char)); + if (text == NULL) + { + ErrCode = ERR_FILE_READ; + Error("Error reading file " DQUOTE("%s"), ErrCode, SrcFileName); + goto ret; + } + + /* copy each string */ + offset = 0; + for (j = 0; j < num_strings; j++) + { + if (strstr(wmops_auto_file[j], "#define FRAMES_PER_SECOND") != NULL) { - ErrCode = ERR_FILE_OPEN; - Error("Cannot Open " DQUOTE("%s"), ErrCode, "wmc_auto.h"); - goto ret; + /* replace the declaration of FRAMES_PER_SECOND with user-defined value */ + sprintf(temp_str, "#define FRAMES_PER_SECOND %-8.1f", frames_per_sec); + strcpy(text + offset, temp_str); + offset += (int) strlen(temp_str); } - - /* Write it */ - file_size = sizeof(wmops_auto_file_h) - 1; - if (fwrite(wmops_auto_file_h, 1, file_size, file) != file_size) + else { - ErrCode = Write_Error(LongFileName); - goto ret; + strcpy(text + offset, wmops_auto_file[j]); + offset += (int) strlen(wmops_auto_file[j]); } + } + + /* Create Target Filename */ + strcpy(TargetFileName, PathName); + + /* strip off surrounding quotes "" */ + strip(TargetFileName, '"'); - /* Close the File */ - fclose(file); + /* Replace '\' Windows Directory Delimiter by UNIX '/' */ + strcsub(TargetFileName, '\\', '/'); + + /* check that there is a proper trailing '/' */ + len = (int)strlen(TargetFileName); + if (TargetFileName[len - 1] != '/') + { + /* add a trailing '/' */ + strcat(TargetFileName, "/"); } else { - /* Create Output Filename */ - strcpy(LongFileName, PathName); - strcat(LongFileName, "/wmc_auto.c"); - - /* Try opening the target file wmc_auto.c */ - if ((file = fopen(LongFileName, "wb")) == NULL) + /* remove all extra trailing '/' */ + while (TargetFileName[len - 2] == '/') { - ErrCode = ERR_FILE_OPEN; - Error("Cannot Open " DQUOTE("%s"), ErrCode, "wmc_auto.c"); - goto ret; - } - - /* Write it */ - file_size = sizeof(wmops_auto_file_c) - 1; - if (fwrite(wmops_auto_file_c, 1, file_size, file) != file_size) - { - ErrCode = Write_Error(LongFileName); - goto ret; + TargetFileName[len - 1] = '\0'; + len--; } + } + strcat(TargetFileName, wmops_auto_files[i]); - /* Close the File */ - fclose(file); + /* Try opening the target file */ + if ((TargetFile = fopen(TargetFileName, "wb")) == NULL) + { + ErrCode = ERR_FILE_OPEN; + Error("Cannot Open " DQUOTE("%s"), ErrCode, TargetFileName); + goto ret; } + + /* Write the whole content to the target file */ + fwrite(text, strlen(text), sizeof(char), TargetFile); + fclose(TargetFile); + free(text); } ret: + return ErrCode; } @@ -1096,6 +1153,7 @@ int main( int argc, char *argv[] ) char LongFileName[MAX_PATH]; char Const_Data_PROM_File[MAX_PATH] = ""; char wmops_output_dir[MAX_PATH]; + float frames_per_sec; T_FILE_BOOK file_book[MAX_RECORDS]; struct stat s; Parse_Context_def ParseContext; @@ -1122,7 +1180,7 @@ int main( int argc, char *argv[] ) if ( ( ErrCode = Parse_Command_Line( argc, argv, &i_cmd_line, &Operation, &Tool_Warning_Mask, Const_Data_PROM_File, - wmops_output_dir) ) != NO_ERR ) + wmops_output_dir, &frames_per_sec) ) != NO_ERR ) { if (ErrCode == ERR_HELP) { @@ -1139,7 +1197,7 @@ int main( int argc, char *argv[] ) Print("\n" "WMC Tool (WMOPS Automatic Instrumentation Tool) v%s - %s\n" "\n" - "(C) 2022 copyright VoiceAge Corporation. All Rights Reserved.\n" + "(C) 2023 copyright VoiceAge Corporation. All Rights Reserved.\n" "\n" "This software is protected by copyright law and by international treaties. The source code, and all of its derivations,\n" "is provided by VoiceAge Corporation under the \"ITU-T Software Tools' General Public License\". Please, read the license file\n" @@ -1254,6 +1312,7 @@ int main( int argc, char *argv[] ) { /* it's an existing directory without file mask -> use *.c as default */ strcpy(file_book[i].pathname, file_book[i].cmd_line_spec); + /* remove the trailing '/', if any */ size = (int)strlen(file_book[i].pathname); while (file_book[i].pathname[size - 1] == '/') @@ -1409,7 +1468,7 @@ int main( int argc, char *argv[] ) if (Operation & OUTPUT_WMOPS_FILES) { /* Yes */ - if ((ErrCode = Output_Wmops_File(wmops_output_dir, (Operation & NO_BACKUP) == 0)) != NO_ERR) + if ((ErrCode = Output_Wmops_File(wmops_output_dir, frames_per_sec, (Operation & NO_BACKUP) == 0)) != NO_ERR) { goto ret; } @@ -1507,6 +1566,10 @@ int main( int argc, char *argv[] ) { fprintf(stdout, "100%% Completed Successfully!\n" ); } + else + { + Print_Error(); + } return ErrCode; } diff --git a/src/wmc_tool/wmc_tool.h b/src/wmc_tool/wmc_tool.h index cda8782..95d961e 100644 --- a/src/wmc_tool/wmc_tool.h +++ b/src/wmc_tool/wmc_tool.h @@ -1,5 +1,5 @@ /* - * (C) 2022 copyright VoiceAge Corporation. All Rights Reserved. + * (C) 2023 copyright VoiceAge Corporation. All Rights Reserved. * * This software is protected by copyright law and by international treaties. The source code, and all of its derivations, * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file @@ -19,7 +19,7 @@ * Switches *-------------------------------------------------------------------*/ -#define WMC_TOOL_VERSION_NO "1.4" /* Current version */ +#define WMC_TOOL_VERSION_NO "1.5" /* Current version */ /*#define DEBUG_PRINT*/ /* For debugging purposes */ /*-------------------------------------------------------------------*