LCOV - code coverage report
Current view: top level - lib_debug - wmc_auto.c (source / functions) Hit Total Coverage
Test: Coverage on main enc/dec/rend @ 3b2f07138c61dcf997bbf4165d0882f794b2995f Lines: 72 72 100.0 %
Date: 2025-05-03 01:55:50 Functions: 0 0 -

          Line data    Source code
       1             : /*
       2             :  * (C) 2024 copyright VoiceAge Corporation. All Rights Reserved.
       3             :  *
       4             :  * This software is protected by copyright law and by international treaties. The source code, and all of its derivations,
       5             :  * is provided by VoiceAge Corporation under the "ITU-T Software Tools' General Public License". Please, read the license file
       6             :  * or refer to ITU-T Recommendation G.191 on "SOFTWARE TOOLS FOR SPEECH AND AUDIO CODING STANDARDS".
       7             :  *
       8             :  * Any use of this software is permitted provided that this notice is not removed and that neither the authors nor
       9             :  * VoiceAge Corporation are deemed to have made any representations as to the suitability of this software
      10             :  * for any purpose nor are held responsible for any defects of this software. THERE IS NO WARRANTY FOR THIS SOFTWARE.
      11             :  *
      12             :  * Authors: Guy Richard, Vladimir Malenovsky (Vladimir.Malenovsky@USherbrooke.ca)
      13             :  */
      14             : 
      15             : #include <stdio.h>
      16             : #include <stdlib.h>
      17             : #include <string.h>
      18             : #include <stdint.h>
      19             : #include <stdarg.h>
      20             : #include <sys/stat.h>
      21             : #include <limits.h>
      22             : 
      23             : #ifndef _MSC_VER
      24             : #include <dirent.h>
      25             : #include <errno.h>
      26             : #else
      27             : #include <windows.h>
      28             : #endif
      29             : 
      30             : #include "options.h"
      31             : #include "wmc_auto.h"
      32             : 
      33             : #define WMC_TOOL_SKIP /* Skip the instrumentation of this file, if invoked by accident */
      34             : 
      35             : #ifndef WMOPS
      36             : int cntr_push_pop = 0; /* global counter for checking balanced push_wmops()/pop_wmops() pairs when WMOPS is not activated */
      37             : #endif
      38             : 
      39             : #ifdef WMOPS
      40             : /*-------------------------------------------------------------------*
      41             :  * Complexity counting tool
      42             :  *--------------------------------------------------------------------*/
      43             : 
      44             : 
      45             : #define MAX_FUNCTION_NAME_LENGTH     200 /* Maximum length of the function name */
      46             : #define MAX_PARAMS_LENGTH            200 /* Maximum length of the function parameter string */
      47             : #define MAX_NUM_RECORDS              300 /* Initial maximum number of records -> might be increased during runtime, if needed */
      48             : #define MAX_NUM_RECORDS_REALLOC_STEP 50  /* When re-allocating the list of records, increase the number of records by this number */
      49             : #define MAX_CALL_TREE_DEPTH          100 /* maximum depth of the function call tree */
      50             : #define DOUBLE_MAX                   0x80000000
      51             : #define FAC                          ( FRAMES_PER_SECOND / 1e6 )
      52             : 
      53             : #define FRAMES_PER_SECOND 50.0
      54             : #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) */
      55             : 
      56             : typedef struct
      57             : {
      58             :     char label[MAX_FUNCTION_NAME_LENGTH];
      59             :     long call_number;
      60             :     long update_cnt;
      61             :     int call_tree[MAX_CALL_TREE_DEPTH];
      62             :     long LastWOper;
      63             :     double start_selfcnt;
      64             :     double current_selfcnt;
      65             :     double max_selfcnt;
      66             :     double min_selfcnt;
      67             :     double tot_selfcnt;
      68             :     double start_cnt; /* The following take into account the decendants */
      69             :     double current_cnt;
      70             :     double max_cnt;
      71             :     double min_cnt;
      72             :     double tot_cnt;
      73             : #ifdef WMOPS_WC_FRAME_ANALYSIS
      74             :     int32_t current_call_number;
      75             :     double wc_cnt;
      76             :     double wc_selfcnt;
      77             :     int32_t wc_call_number;
      78             : #endif
      79             : } wmops_record;
      80             : 
      81             : double ops_cnt;
      82             : double inst_cnt[NUM_INST];
      83             : 
      84             : static wmops_record *wmops = NULL;
      85             : static int num_wmops_records, max_num_wmops_records;
      86             : static int current_record;
      87             : static long update_cnt;
      88             : static double start_cnt;
      89             : static double max_cnt;
      90             : static double min_cnt;
      91             : static double inst_cnt_wc[NUM_INST];
      92             : static long fnum_cnt_wc;
      93             : static int *wmops_caller_stack = NULL, wmops_caller_stack_index, max_wmops_caller_stack_index = 0;
      94             : static int *heap_allocation_call_tree = NULL, heap_allocation_call_tree_size = 0, heap_allocation_call_tree_max_size = 0;
      95             : 
      96             : static BASIC_OP op_weight = {
      97             :     1, 1, 1, 1, 1,
      98             :     1, 1, 1, 1, 1,
      99             :     1, 1, 1, 1, 1,
     100             :     1, 1, 2, 2, 1,
     101             :     1, 1, 1, 2, 1,
     102             : 
     103             :     1, 1, 1, 2, 1,
     104             :     1, 1, 18, 1, 1,
     105             :     1, 1, 1, 1, 1,
     106             :     1, 1, 1, 1, 1,
     107             :     2, 2, 2, 2, 1,
     108             : 
     109             :     1, 1, 1, 1, 1,
     110             :     1, 1, 1, 2,
     111             :     1, 2, 2, 2, 1,
     112             :     1, 1, 1, 1, 1,
     113             :     1, 1, 1, 1, 1,
     114             : 
     115             :     1, 1, 1, 1, 3,
     116             :     3, 3, 3, 1, 1,
     117             :     1, 1, 1, 1, 1,
     118             :     1, 1, 1, 3, 2,
     119             :     2, 6, 3, 3, 2,
     120             : 
     121             :     1, 32, 1
     122             : 
     123             : /* New complex basops */
     124             : #ifdef COMPLEX_OPERATOR
     125             :     ,
     126             :     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1
     127             : 
     128             :     ,
     129             :     1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1
     130             : 
     131             : #endif /* #ifdef COMPLEX_OPERATOR */
     132             : 
     133             : #ifdef ENH_64_BIT_OPERATOR
     134             :     /* Weights of new 64 bit basops */
     135             :     ,
     136             :     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
     137             : #endif /* #ifdef ENH_64_BIT_OPERATOR */
     138             : 
     139             : #ifdef ENH_32_BIT_OPERATOR
     140             :     ,
     141             :     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
     142             : #endif /* #ifdef ENH_32_BIT_OPERATOR */
     143             : 
     144             : #ifdef ENH_U_32_BIT_OPERATOR
     145             :     ,
     146             :     1, 1, 1, 2, 2, 1, 1
     147             : #endif /* #ifdef ENH_U_32_BIT_OPERATOR */
     148             : 
     149             : #ifdef CONTROL_CODE_OPS
     150             :     ,
     151             :     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
     152             : #endif /* #ifdef CONTROL_CODE_OPS */
     153             : };
     154             : 
     155             : BASIC_OP *multiCounter = NULL;
     156             : unsigned int currCounter = 0;
     157             : long funcid_total_wmops_at_last_call_to_else;
     158             : char func_name_where_last_call_to_else_occurred[MAX_FUNCTION_NAME_LENGTH + 1];
     159             : 
     160             : void reset_wmops( void )
     161             : {
     162             :     int i, j;
     163             : 
     164             :     num_wmops_records = 0;
     165             :     max_num_wmops_records = MAX_NUM_RECORDS;
     166             :     current_record = -1;
     167             :     update_cnt = 0;
     168             : 
     169             :     max_cnt = 0.0;
     170             :     min_cnt = DOUBLE_MAX;
     171             :     start_cnt = 0.0;
     172             :     ops_cnt = 0.0;
     173             : 
     174             :     /* allocate the list of WMOPS records */
     175             :     if ( wmops == NULL )
     176             :     {
     177             :         wmops = (wmops_record *) malloc( max_num_wmops_records * sizeof( wmops_record ) );
     178             :     }
     179             : 
     180             :     if ( wmops == NULL )
     181             :     {
     182             :         fprintf( stderr, "Error: Unable to Allocate List of WMOPS Records!" );
     183             :         exit( -1 );
     184             :     }
     185             : 
     186             :     /* allocate the list of BASOP WMOPS records */
     187             :     if ( multiCounter == NULL )
     188             :     {
     189             :         multiCounter = (BASIC_OP *) malloc( max_num_wmops_records * sizeof( BASIC_OP ) );
     190             :     }
     191             : 
     192             :     if ( multiCounter == NULL )
     193             :     {
     194             :         fprintf( stderr, "Error: Unable to Allocate the BASOP WMOPS counter!" );
     195             :         exit( -1 );
     196             :     }
     197             : 
     198             :     /* initilize the list of WMOPS records */
     199             :     /* initilize BASOP operation counters */
     200             :     for ( i = 0; i < max_num_wmops_records; i++ )
     201             :     {
     202             :         strcpy( &wmops[i].label[0], "\0" );
     203             :         wmops[i].call_number = 0;
     204             :         wmops[i].update_cnt = 0;
     205             :         for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ )
     206             :         {
     207             :             wmops[i].call_tree[j] = -1;
     208             :         }
     209             :         wmops[i].start_selfcnt = 0.0;
     210             :         wmops[i].current_selfcnt = 0.0;
     211             :         wmops[i].max_selfcnt = 0.0;
     212             :         wmops[i].min_selfcnt = DOUBLE_MAX;
     213             :         wmops[i].tot_selfcnt = 0.0;
     214             :         wmops[i].start_cnt = 0.0;
     215             :         wmops[i].current_cnt = 0.0;
     216             :         wmops[i].max_cnt = 0.0;
     217             :         wmops[i].min_cnt = DOUBLE_MAX;
     218             :         wmops[i].tot_cnt = 0.0;
     219             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     220             :         wmops[i].wc_cnt = 0.0;
     221             :         wmops[i].wc_selfcnt = 0.0;
     222             :         wmops[i].current_call_number = 0;
     223             :         wmops[i].wc_call_number = -1;
     224             : #endif
     225             : 
     226             :         /* Reset BASOP operation counter */
     227             :         Reset_BASOP_WMOPS_counter( i );
     228             :     }
     229             : 
     230             :     /* allocate the list of wmops callers to track the sequence of function calls */
     231             :     wmops_caller_stack_index = 0;
     232             :     max_wmops_caller_stack_index = MAX_NUM_RECORDS;
     233             :     if ( wmops_caller_stack == NULL )
     234             :     {
     235             :         wmops_caller_stack = malloc( max_wmops_caller_stack_index * sizeof( int ) );
     236             :     }
     237             : 
     238             :     if ( wmops_caller_stack == NULL )
     239             :     {
     240             :         fprintf( stderr, "Error: Unable to Allocate List of WMOPS Callers!" );
     241             :         exit( -1 );
     242             :     }
     243             : 
     244             :     for ( i = 0; i < max_wmops_caller_stack_index; i++ )
     245             :     {
     246             :         wmops_caller_stack[i] = -1;
     247             :     }
     248             : 
     249             :     return;
     250             : }
     251             : 
     252             : void push_wmops_fct( const char *label, ... )
     253             : {
     254             :     int new_flag;
     255             :     int i, j, index_record;
     256             :     long tot;
     257             :     va_list arg;
     258             :     char func_name[MAX_FUNCTION_NAME_LENGTH] = "";
     259             : 
     260             :     /* concatenate all function name labels into a single string */
     261             :     va_start( arg, label );
     262             :     while ( label )
     263             :     {
     264             :         strcat( func_name, label );
     265             :         label = va_arg( arg, const char * );
     266             :     }
     267             :     va_end( arg );
     268             : 
     269             :     /* Check, if this is a new function label */
     270             :     new_flag = 1;
     271             :     for ( i = 0; i < num_wmops_records; i++ )
     272             :     {
     273             :         if ( strcmp( wmops[i].label, func_name ) == 0 )
     274             :         {
     275             :             new_flag = 0;
     276             :             break;
     277             :         }
     278             :     }
     279             :     index_record = i;
     280             : 
     281             :     /* Create a new WMOPS record in the list */
     282             :     if ( new_flag )
     283             :     {
     284             :         if ( num_wmops_records >= max_num_wmops_records )
     285             :         {
     286             :             /* There is no room for a new WMOPS record -> reallocate the list */
     287             :             max_num_wmops_records += MAX_NUM_RECORDS_REALLOC_STEP;
     288             :             wmops = realloc( wmops, max_num_wmops_records * sizeof( wmops_record ) );
     289             :             multiCounter = realloc( multiCounter, max_num_wmops_records * sizeof( BASIC_OP ) );
     290             :         }
     291             : 
     292             :         /* initilize the new WMOPS record */
     293             :         strcpy( &wmops[index_record].label[0], "\0" );
     294             :         wmops[index_record].call_number = 0;
     295             :         wmops[index_record].update_cnt = 0;
     296             :         for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ )
     297             :         {
     298             :             wmops[index_record].call_tree[j] = -1;
     299             :         }
     300             :         wmops[index_record].start_selfcnt = 0.0;
     301             :         wmops[index_record].current_selfcnt = 0.0;
     302             :         wmops[index_record].max_selfcnt = 0.0;
     303             :         wmops[index_record].min_selfcnt = DOUBLE_MAX;
     304             :         wmops[index_record].tot_selfcnt = 0.0;
     305             :         wmops[index_record].start_cnt = 0.0;
     306             :         wmops[index_record].current_cnt = 0.0;
     307             :         wmops[index_record].max_cnt = 0.0;
     308             :         wmops[index_record].min_cnt = DOUBLE_MAX;
     309             :         wmops[index_record].tot_cnt = 0.0;
     310             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     311             :         wmops[index_record].wc_cnt = 0.0;
     312             :         wmops[index_record].wc_selfcnt = 0.0;
     313             :         wmops[index_record].current_call_number = 0;
     314             :         wmops[index_record].wc_call_number = -1;
     315             : #endif
     316             : 
     317             :         /* Reset BASOP operation counter */
     318             :         Reset_BASOP_WMOPS_counter( index_record );
     319             : 
     320             :         strcpy( wmops[index_record].label, func_name );
     321             : 
     322             :         num_wmops_records++;
     323             :     }
     324             : 
     325             :     /* Update the WMOPS context info of the old record before switching to the new one */
     326             :     if ( current_record >= 0 )
     327             :     {
     328             :         if ( wmops_caller_stack_index >= max_wmops_caller_stack_index )
     329             :         {
     330             :             /* There is no room for a new record -> reallocate the list */
     331             :             max_wmops_caller_stack_index += MAX_NUM_RECORDS_REALLOC_STEP;
     332             :             wmops_caller_stack = realloc( wmops_caller_stack, max_wmops_caller_stack_index * sizeof( int ) );
     333             :         }
     334             :         wmops_caller_stack[wmops_caller_stack_index++] = current_record;
     335             : 
     336             :         /* add the BASOP complexity to the counter and update the old WMOPS counter */
     337             :         tot = DeltaWeightedOperation( current_record );
     338             :         ops_cnt += tot;
     339             :         wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt;
     340             : 
     341             :         /* update call tree */
     342             :         for ( j = 0; j < MAX_CALL_TREE_DEPTH; j++ )
     343             :         {
     344             :             if ( wmops[index_record].call_tree[j] == current_record )
     345             :             {
     346             :                 break;
     347             :             }
     348             :             else if ( wmops[index_record].call_tree[j] == -1 )
     349             :             {
     350             :                 wmops[index_record].call_tree[j] = current_record;
     351             :                 break;
     352             :             }
     353             :         }
     354             :     }
     355             : 
     356             :     /* Need to reset the BASOP operation counter of the 0th record in every push_wmops() */
     357             :     /* because currCounter can never be -1 */
     358             :     if ( current_record == -1 && index_record == 0 )
     359             :     {
     360             :         wmops[index_record].LastWOper = TotalWeightedOperation( index_record );
     361             :     }
     362             : 
     363             :     /* switch to the new record */
     364             :     current_record = index_record;
     365             :     wmops[index_record].start_selfcnt = ops_cnt;
     366             :     wmops[index_record].start_cnt = ops_cnt;
     367             :     wmops[index_record].call_number++;
     368             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     369             :     wmops[index_record].current_call_number++;
     370             : #endif
     371             : 
     372             :     /* set the ID of the current BASOP operations counter */
     373             :     currCounter = index_record;
     374             : 
     375             :     return;
     376             : }
     377             : 
     378             : void pop_wmops( void )
     379             : {
     380             :     long tot;
     381             : 
     382             :     /* Check for underflow */
     383             :     if ( current_record < 0 )
     384             :     {
     385             :         fprintf( stdout, "\r pop_wmops(): stack underflow, too many calls to pop_wmops()\n" );
     386             :         exit( -1 );
     387             :     }
     388             : 
     389             :     /* add the BASOP complexity to the counter */
     390             :     tot = DeltaWeightedOperation( currCounter );
     391             :     ops_cnt += tot;
     392             : 
     393             :     /* update count of current record */
     394             :     wmops[current_record].current_selfcnt += ops_cnt - wmops[current_record].start_selfcnt;
     395             :     wmops[current_record].current_cnt += ops_cnt - wmops[current_record].start_cnt;
     396             : 
     397             :     /* Get back previous context from stack */
     398             :     if ( wmops_caller_stack_index > 0 )
     399             :     {
     400             :         current_record = wmops_caller_stack[--wmops_caller_stack_index];
     401             :         wmops[current_record].start_selfcnt = ops_cnt;
     402             :     }
     403             :     else
     404             :     {
     405             :         current_record = -1;
     406             :     }
     407             : 
     408             :     /* set the ID of the previous BASOP operations counter */
     409             :     if ( current_record == -1 )
     410             :     {
     411             :         currCounter = 0; /* Note: currCounter cannot be set to -1 because it's defined as unsigned int ! */
     412             :     }
     413             :     else
     414             :     {
     415             :         currCounter = current_record;
     416             :     }
     417             : 
     418             :     return;
     419             : }
     420             : 
     421             : 
     422             : void update_wmops( void )
     423             : {
     424             :     int i;
     425             :     double current_cnt;
     426             : #ifdef WMOPS_PER_FRAME
     427             :     static FILE *fid = NULL;
     428             :     const char filename[] = "wmops_analysis";
     429             :     float tmpF;
     430             : #endif
     431             : 
     432             :     if ( wmops_caller_stack_index != 0 )
     433             :     {
     434             :         fprintf( stdout, "update_wmops(): WMOPS caller stack corrupted - check that all push_wmops() are matched with pop_wmops()!\n" );
     435             :         exit( -1 );
     436             :     }
     437             : 
     438             : #ifdef WMOPS_PER_FRAME
     439             :     /* Check, if the output file has already been opened */
     440             :     if ( fid == NULL )
     441             :     {
     442             :         fid = fopen( filename, "wb" );
     443             : 
     444             :         if ( fid == NULL )
     445             :         {
     446             :             fprintf( stderr, "\nCannot open %s!\n\n", filename );
     447             :             exit( -1 );
     448             :         }
     449             :     }
     450             : 
     451             :     /* Write current complexity to the external file */
     452             :     tmpF = (float) ( FAC * wmops[0].current_cnt );
     453             :     fwrite( &tmpF, sizeof( float ), 1, fid );
     454             : #endif
     455             : 
     456             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     457             :     if ( ops_cnt - start_cnt > max_cnt )
     458             :     {
     459             :         for ( i = 0; i < num_wmops_records; i++ )
     460             :         {
     461             :             wmops[i].wc_cnt = wmops[i].current_cnt;
     462             :             wmops[i].wc_selfcnt = wmops[i].current_selfcnt;
     463             :             wmops[i].wc_call_number = wmops[i].current_call_number;
     464             :         }
     465             :     }
     466             : #endif
     467             : 
     468             :     for ( i = 0; i < num_wmops_records; i++ )
     469             :     {
     470             :         wmops[i].tot_selfcnt += wmops[i].current_selfcnt;
     471             :         wmops[i].tot_cnt += wmops[i].current_cnt;
     472             : 
     473             :         if ( wmops[i].current_selfcnt > 0 )
     474             :         {
     475             :             if ( wmops[i].current_selfcnt > wmops[i].max_selfcnt )
     476             :             {
     477             :                 wmops[i].max_selfcnt = wmops[i].current_selfcnt;
     478             :             }
     479             : 
     480             :             if ( wmops[i].current_selfcnt < wmops[i].min_selfcnt )
     481             :             {
     482             :                 wmops[i].min_selfcnt = wmops[i].current_selfcnt;
     483             :             }
     484             :         }
     485             : 
     486             :         wmops[i].current_selfcnt = 0;
     487             : 
     488             :         if ( wmops[i].current_cnt > 0 )
     489             :         {
     490             :             if ( wmops[i].current_cnt > wmops[i].max_cnt )
     491             :             {
     492             :                 wmops[i].max_cnt = wmops[i].current_cnt;
     493             :             }
     494             : 
     495             : 
     496             :             if ( wmops[i].current_cnt < wmops[i].min_cnt )
     497             :             {
     498             :                 wmops[i].min_cnt = wmops[i].current_cnt;
     499             :             }
     500             : 
     501             :             wmops[i].update_cnt++;
     502             :         }
     503             : 
     504             :         wmops[i].current_cnt = 0;
     505             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     506             :         wmops[i].current_call_number = 0;
     507             : #endif
     508             : 
     509             :         /* reset the BASOP operations counter */
     510             :         Reset_BASOP_WMOPS_counter( i );
     511             :     }
     512             : 
     513             :     current_cnt = ops_cnt - start_cnt;
     514             :     if ( current_cnt > max_cnt )
     515             :     {
     516             :         max_cnt = current_cnt;
     517             : 
     518             :         for ( i = 0; i < NUM_INST; i++ )
     519             :         {
     520             :             inst_cnt_wc[i] = inst_cnt[i];
     521             :         }
     522             : 
     523             :         fnum_cnt_wc = update_cnt + 1;
     524             :     }
     525             : 
     526             :     if ( current_cnt < min_cnt )
     527             :     {
     528             :         min_cnt = current_cnt;
     529             :     }
     530             : 
     531             :     for ( i = 0; i < NUM_INST; i++ )
     532             :     {
     533             :         inst_cnt[i] = 0.0;
     534             :     }
     535             : 
     536             :     start_cnt = ops_cnt;
     537             : 
     538             :     /* increment frame counter */
     539             :     update_cnt++;
     540             : 
     541             :     return;
     542             : }
     543             : 
     544             : void print_wmops( void )
     545             : {
     546             :     int i, label_len, max_label_len;
     547             : 
     548             :     char *sfmts = "%*s %8s %8s %7s %7s\n";
     549             :     char *dfmts = "%*s %8.2f %8.3f %7.3f %7.3f\n";
     550             :     char *sfmt = "%*s %8s %8s %7s %7s  %7s %7s %7s\n";
     551             :     char *dfmt = "%*s %8.2f %8.3f %7.3f %7.3f  %7.3f %7.3f %7.3f\n";
     552             : 
     553             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     554             :     int j;
     555             :     char *sfmtt = "%20s %4s %15s\n";
     556             :     char *dfmtt = "%20s %4d  ";
     557             : #endif
     558             : 
     559             :     /* calculate maximum label length for compact prinout */
     560             :     max_label_len = 0;
     561             :     for ( i = 0; i < num_wmops_records; i++ )
     562             :     {
     563             :         label_len = strlen( wmops[i].label );
     564             :         if ( label_len > max_label_len )
     565             :         {
     566             :             max_label_len = label_len;
     567             :         }
     568             :     }
     569             :     max_label_len += 4;
     570             : 
     571             :     fprintf( stdout, "\n\n --- Complexity analysis [WMOPS] ---  \n\n" );
     572             : 
     573             :     fprintf( stdout, "%*s %33s  %23s\n", max_label_len, "", "|------  SELF  ------|", "|---  CUMULATIVE  ---|" );
     574             :     fprintf( stdout, sfmt, max_label_len, "        routine", " calls", "  min ", "  max ", "  avg ", "  min ", "  max ", "  avg " );
     575             :     fprintf( stdout, sfmt, max_label_len, "---------------", "------", "------", "------", "------", "------", "------", "------" );
     576             : 
     577             :     for ( i = 0; i < num_wmops_records; i++ )
     578             :     {
     579             :         fprintf( stdout, dfmt, max_label_len, wmops[i].label, update_cnt == 0 ? 0 : (float) wmops[i].call_number / update_cnt,
     580             :                  wmops[i].min_selfcnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_selfcnt,
     581             :                  FAC * wmops[i].max_selfcnt,
     582             :                  wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_selfcnt / wmops[i].update_cnt,
     583             :                  wmops[i].min_cnt == DOUBLE_MAX ? 0 : FAC * wmops[i].min_cnt,
     584             :                  FAC * wmops[i].max_cnt,
     585             :                  wmops[i].update_cnt == 0 ? 0 : FAC * wmops[i].tot_cnt / wmops[i].update_cnt );
     586             :     }
     587             : 
     588             :     fprintf( stdout, sfmts, max_label_len, "---------------", "------", "------", "------", "------" );
     589             :     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 );
     590             :     fprintf( stdout, "\n" );
     591             : 
     592             : #ifdef WMOPS_WC_FRAME_ANALYSIS
     593             :     fprintf( stdout, "\nComplexity analysis for the worst-case frame %ld:\n\n", fnum_cnt_wc );
     594             :     fprintf( stdout, "%*s %8s %10s %12s\n", max_label_len, "        routine", " calls", " SELF", "  CUMULATIVE" );
     595             :     fprintf( stdout, "%*s %8s %10s   %10s\n", max_label_len, "---------------", "------", "------", "----------" );
     596             : 
     597             :     for ( i = 0; i < num_wmops_records; i++ )
     598             :     {
     599             :         if ( wmops[i].wc_call_number > 0 )
     600             :         {
     601             :             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 );
     602             :         }
     603             :     }
     604             : 
     605             :     fprintf( stdout, "\nCall tree for the worst-case frame %ld:\n\n", fnum_cnt_wc );
     606             :     fprintf( stdout, sfmtt, "       function", "num", "called by     " );
     607             :     fprintf( stdout, sfmtt, "---------------", "---", "--------------" );
     608             : 
     609             :     for ( i = 0; i < num_wmops_records; i++ )
     610             :     {
     611             :         if ( wmops[i].wc_call_number > 0 )
     612             :         {
     613             :             fprintf( stdout, dfmtt, wmops[i].label, i );
     614             :             for ( j = 0; wmops[i].call_tree[j] != -1 && j < MAX_CALL_TREE_DEPTH; j++ )
     615             :             {
     616             :                 if ( j != 0 )
     617             :                 {
     618             :                     fprintf( stdout, ", " );
     619             :                 }
     620             :                 fprintf( stdout, "%d", wmops[i].call_tree[j] );
     621             :             }
     622             :             fprintf( stdout, "\n" );
     623             :         }
     624             :     }
     625             : 
     626             :     fprintf( stdout, "\n\n" );
     627             : 
     628             :     fprintf( stdout, "\nInstruction type analysis for the worst-case frame %ld:\n\n", fnum_cnt_wc );
     629             :     for ( i = 0; i < NUM_INST; i++ )
     630             :     {
     631             :         switch ( (enum instructions) i )
     632             :         {
     633             :             case _ADD:
     634             :                 fprintf( stdout, "\tAdds:          %12.1f\n", inst_cnt_wc[i] );
     635             :                 break;
     636             :             case _ABS:
     637             :                 fprintf( stdout, "\tAbsolutes:     %12.1f\n", inst_cnt_wc[i] );
     638             :                 break;
     639             :             case _MULT:
     640             :                 fprintf( stdout, "\tMultiplies:    %12.1f\n", inst_cnt_wc[i] );
     641             :                 break;
     642             :             case _MAC:
     643             :                 fprintf( stdout, "\tMACs:          %12.1f\n", inst_cnt_wc[i] );
     644             :                 break;
     645             :             case _MOVE:
     646             :                 fprintf( stdout, "\tMoves:         %12.1f\n", inst_cnt_wc[i] );
     647             :                 break;
     648             :             case _STORE:
     649             :                 fprintf( stdout, "\tStores:        %12.1f\n", inst_cnt_wc[i] );
     650             :                 break;
     651             :             case _LOGIC:
     652             :                 fprintf( stdout, "\tLogicals:      %12.1f\n", inst_cnt_wc[i] );
     653             :                 break;
     654             :             case _SHIFT:
     655             :                 fprintf( stdout, "\tShifts:        %12.1f\n", inst_cnt_wc[i] );
     656             :                 break;
     657             :             case _BRANCH:
     658             :                 fprintf( stdout, "\tBranches:      %12.1f\n", inst_cnt_wc[i] );
     659             :                 break;
     660             :             case _DIV:
     661             :                 fprintf( stdout, "\tDivisions:     %12.1f\n", inst_cnt_wc[i] );
     662             :                 break;
     663             :             case _SQRT:
     664             :                 fprintf( stdout, "\tSquare Root:   %12.1f\n", inst_cnt_wc[i] );
     665             :                 break;
     666             :             case _TRANS:
     667             :                 fprintf( stdout, "\tTrans:         %12.1f\n", inst_cnt_wc[i] );
     668             :                 break;
     669             :             case _FUNC:
     670             :                 fprintf( stdout, "\tFunc Call:     %12.1f\n", inst_cnt_wc[i] );
     671             :                 break;
     672             :             case _LOOP:
     673             :                 fprintf( stdout, "\tLoop Init:     %12.1f\n", inst_cnt_wc[i] );
     674             :                 break;
     675             :             case _INDIRECT:
     676             :                 fprintf( stdout, "\tIndirect Addr: %12.1f\n", inst_cnt_wc[i] );
     677             :                 break;
     678             :             case _PTR_INIT:
     679             :                 fprintf( stdout, "\tPointer Init:  %12.1f\n", inst_cnt_wc[i] );
     680             :                 break;
     681             :             case _TEST:
     682             :                 fprintf( stdout, "\tExtra condit.: %12.1f\n", inst_cnt_wc[i] );
     683             :                 break;
     684             :             case _POWER:
     685             :                 fprintf( stdout, "\tExponential:   %12.1f\n", inst_cnt_wc[i] );
     686             :                 break;
     687             :             case _LOG:
     688             :                 fprintf( stdout, "\tLogarithm:     %12.1f\n", inst_cnt_wc[i] );
     689             :                 break;
     690             :             case _MISC:
     691             :                 fprintf( stdout, "\tAll other op.: %12.1f\n", inst_cnt_wc[i] );
     692             :                 break;
     693             :             default:
     694             :                 fprintf( stdout, "\tERROR: Invalid instruction type: %d\n\n", i );
     695             :         }
     696             :     }
     697             : #endif
     698             : 
     699             :     /* De-allocate the list of wmops record */
     700             :     if ( wmops != NULL )
     701             :     {
     702             :         free( wmops );
     703             :     }
     704             : 
     705             :     /* De-allocate the list of wmops caller functions */
     706             :     if ( wmops_caller_stack != NULL )
     707             :     {
     708             :         free( wmops_caller_stack );
     709             :     }
     710             : 
     711             :     /* De-allocate the BASOP WMOPS counter */
     712             :     if ( multiCounter != NULL )
     713             :     {
     714             :         free( multiCounter );
     715             :     }
     716             : 
     717             :     return;
     718             : }
     719             : 
     720             : /*-------------------------------------------------------------------*
     721             :  * Memory counting tool measuring RAM usage (stack and heap)
     722             :  *
     723             :  * Maximum RAM is measured by monitoring the total allocated memory (stack and heap) in each frame.
     724             :  *
     725             :  * 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
     726             :  * with a macro 'func_start_' which is inserted automatically to all functions during the instrumentation process.
     727             :  *
     728             :  * 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
     729             :  * updated each time when the macros malloc_() or calloc_() is invoked. The macros 'malloc_ and calloc_' are inserted automatically during the instrumentation process.
     730             :  * 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
     731             :  * within a single frame. Inter-frame heap, on the contrary, refers to heap memory which is reserved for more than one frame.
     732             :  *
     733             :  * 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.
     734             :  * 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).
     735             :  * 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'
     736             :  * is activated, detailed information is printed
     737             :  *
     738             :  * The macro 'WMOPS' needs to be activated to enable memory counting. To avoid the instrumentation of malloc()/calloc()/free() calls, use
     739             :  * #define WMC_TOOL_SKIP ... #undef WMC_TOOL_SKIP macro pair around the malloc(), calloc() and free().
     740             :  *--------------------------------------------------------------------*/
     741             : 
     742             : 
     743             : /* This is the value (in bytes) towards which the block size is rounded. For example, a block of 123 bytes, when using
     744             :    a 32 bits system, will end up taking 124 bytes since the last unused byte cannot be used for another block. */
     745             : #ifdef MEM_ALIGN_64BITS
     746             : #define BLOCK_ROUNDING 8 /* Align on 64 Bits */
     747             : #else
     748             : #define BLOCK_ROUNDING 4 /* Align on 32 Bits */
     749             : #endif
     750             : 
     751             : #define N_32BITS_BLOCKS ( BLOCK_ROUNDING / sizeof( int32_t ) )
     752             : 
     753             : #define MAGIC_VALUE_OOB  0x12A534F0           /* Signature value which is inserted before and after each allocated memory block, used to detect out-of-bound access */
     754             : #define MAGIC_VALUE_USED ( ~MAGIC_VALUE_OOB ) /* Value used to pre-fill allocated memory blocks, used to calculate actual memory usage */
     755             : #define OOB_START        0x1                  /* int indicating out-of-bounds access before memory block */
     756             : #define OOB_END          0x2                  /* int indicating out-of-bounds access after memory block */
     757             : 
     758             : #define ROUND_BLOCK_SIZE( n ) ( ( ( n ) + BLOCK_ROUNDING - 1 ) & ~( BLOCK_ROUNDING - 1 ) )
     759             : #define IS_CALLOC( str )      ( str[0] == 'c' )
     760             : 
     761             : #ifdef MEM_COUNT_DETAILS
     762             : const char *csv_filename = "mem_analysis.csv";
     763             : static FILE *fid_csv_filename = NULL;
     764             : #endif
     765             : 
     766             : typedef struct
     767             : {
     768             :     char function_name[MAX_FUNCTION_NAME_LENGTH + 1];
     769             :     int16_t *stack_ptr;
     770             : } caller_info;
     771             : 
     772             : static caller_info *stack_callers[2] = { NULL, NULL };
     773             : 
     774             : static int16_t *ptr_base_stack = 0;    /* Pointer to the bottom of stack (base pointer). Stack grows up. */
     775             : static int16_t *ptr_current_stack = 0; /* Pointer to the current stack pointer */
     776             : static int16_t *ptr_max_stack = 0;     /* Pointer to the maximum stack pointer (the farest point from the bottom of stack) */
     777             : static int32_t wc_stack_frame = 0;     /* Frame corresponding to the worst-case stack usage */
     778             : static int current_calls = 0, max_num_calls = MAX_NUM_RECORDS;
     779             : static char location_max_stack[256] = "undefined";
     780             : 
     781             : typedef struct
     782             : {
     783             :     char name[MAX_FUNCTION_NAME_LENGTH + 1]; /* +1 for NUL */
     784             :     char params[1 + MAX_PARAMS_LENGTH + 1];  /* +1 for 'm'/'c' alloc & +1 for NUL */
     785             :     unsigned long hash;
     786             :     int lineno;
     787             :     void *block_ptr;
     788             :     int block_size;
     789             :     unsigned long total_block_size; /* Cumulative sum of the allocated size in the session */
     790             :     unsigned long total_used_size;  /* Cumulative sum of the used size in the session */
     791             :     int wc_heap_size_intra_frame;   /* Worst-Case Intra-Frame Heap Size */
     792             :     int wc_heap_size_inter_frame;   /* Worst-Case Inter-Frame Heap Size */
     793             :     int frame_allocated;            /* Frame number in which the Memory Block has been allocated (-1 if not allocated at the moment) */
     794             :     int OOB_Flag;
     795             :     int noccurances; /* Number of times that the memory block has been allocated in a frame */
     796             : } allocator_record;
     797             : 
     798             : allocator_record *allocation_list = NULL;
     799             : 
     800             : static int Num_Records, Max_Num_Records;
     801             : static size_t Stat_Cnt_Size = USE_BYTES;
     802             : static const char *Count_Unit[] = { "bytes", "words", "words", "words" };
     803             : 
     804             : static int32_t wc_ram_size, wc_ram_frame;
     805             : static int32_t current_heap_size;
     806             : 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;
     807             : static int *list_current_inter_frame_heap, n_items_current_inter_frame_heap, max_items_current_inter_frame_heap, size_current_inter_frame_heap;
     808             : 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;
     809             : 
     810             : /* Local Functions */
     811             : static unsigned long malloc_hash( const char *func_name, int func_lineno, char *size_str );
     812             : allocator_record *get_mem_record( unsigned long *hash, const char *func_name, int func_lineno, char *size_str, int *index_record );
     813             : static void *mem_alloc_block( size_t size, const char *size_str );
     814             : 
     815             : /*-------------------------------------------------------------------*
     816             :  * reset_mem()
     817             :  *
     818             :  * Initialize/reset memory counting tool (stack and heap)
     819             :  *--------------------------------------------------------------------*/
     820             : 
     821             : void reset_mem( Counting_Size cnt_size )
     822             : {
     823             :     int16_t something;
     824             :     size_t tmp_size;
     825             : 
     826             :     /* initialize list of stack records */
     827             :     if ( stack_callers[0] == NULL )
     828             :     {
     829             :         stack_callers[0] = malloc( MAX_NUM_RECORDS * sizeof( caller_info ) );
     830             :         stack_callers[1] = malloc( MAX_NUM_RECORDS * sizeof( caller_info ) );
     831             :     }
     832             : 
     833             :     if ( stack_callers[0] == NULL || stack_callers[1] == NULL )
     834             :     {
     835             :         fprintf( stderr, "Error: Unable to Allocate List of Stack Records!" );
     836             :         exit( -1 );
     837             :     }
     838             : 
     839             :     current_calls = 0;
     840             :     max_num_calls = MAX_NUM_RECORDS;
     841             : 
     842             :     /* initialize stack pointers */
     843             :     ptr_base_stack = &something;
     844             :     ptr_max_stack = ptr_base_stack;
     845             :     ptr_current_stack = ptr_base_stack;
     846             : 
     847             :     /* initialize the unit of memory block size */
     848             :     Stat_Cnt_Size = cnt_size;
     849             : 
     850             :     /* Check, if sizeof(int32_t) is 4 bytes */
     851             :     tmp_size = sizeof( int32_t );
     852             :     if ( tmp_size != 4 )
     853             :     {
     854             :         fprintf( stderr, "Error: Expecting 'int32_t' to be a 32 Bits Integer!" );
     855             :         exit( -1 );
     856             :     }
     857             : 
     858             :     /* create allocation list for malloc() memory blocks */
     859             :     if ( allocation_list == NULL )
     860             :     {
     861             :         allocation_list = malloc( MAX_NUM_RECORDS * sizeof( allocator_record ) );
     862             :     }
     863             : 
     864             :     if ( allocation_list == NULL )
     865             :     {
     866             :         fprintf( stderr, "Error: Unable to Create List of Memory Blocks!" );
     867             :         exit( -1 );
     868             :     }
     869             : 
     870             :     Num_Records = 0;
     871             :     Max_Num_Records = MAX_NUM_RECORDS;
     872             : 
     873             :     wc_ram_size = 0;
     874             :     wc_ram_frame = -1;
     875             :     current_heap_size = 0;
     876             : 
     877             :     /* heap allocation tree */
     878             :     heap_allocation_call_tree_max_size = MAX_NUM_RECORDS;
     879             :     if ( heap_allocation_call_tree == NULL )
     880             :     {
     881             :         heap_allocation_call_tree = (int *) malloc( heap_allocation_call_tree_max_size * sizeof( int ) );
     882             :         memset( heap_allocation_call_tree, -1, heap_allocation_call_tree_max_size * sizeof( int ) );
     883             :     }
     884             :     heap_allocation_call_tree_size = 0;
     885             : 
     886             :     /* wc intra-frame heap */
     887             :     max_items_wc_intra_frame_heap = MAX_NUM_RECORDS;
     888             :     if ( list_wc_intra_frame_heap == NULL )
     889             :     {
     890             :         list_wc_intra_frame_heap = (int *) malloc( max_items_wc_intra_frame_heap * sizeof( int ) );
     891             :         memset( list_wc_intra_frame_heap, -1, max_items_wc_intra_frame_heap * sizeof( int ) );
     892             :     }
     893             :     n_items_wc_intra_frame_heap = 0;
     894             :     size_wc_intra_frame_heap = 0;
     895             :     location_wc_intra_frame_heap = -1;
     896             : 
     897             :     /* current inter-frame heap */
     898             :     max_items_current_inter_frame_heap = MAX_NUM_RECORDS;
     899             :     if ( list_current_inter_frame_heap == NULL )
     900             :     {
     901             :         list_current_inter_frame_heap = (int *) malloc( max_items_current_inter_frame_heap * sizeof( int ) );
     902             :         memset( list_current_inter_frame_heap, -1, max_items_current_inter_frame_heap * sizeof( int ) );
     903             :     }
     904             :     n_items_current_inter_frame_heap = 0;
     905             :     size_current_inter_frame_heap = 0;
     906             : 
     907             :     /* wc inter-frame heap */
     908             :     max_items_wc_inter_frame_heap = MAX_NUM_RECORDS;
     909             :     if ( list_wc_inter_frame_heap == NULL )
     910             :     {
     911             :         list_wc_inter_frame_heap = (int *) malloc( max_items_wc_inter_frame_heap * sizeof( int ) );
     912             :         memset( list_wc_inter_frame_heap, -1, max_items_wc_inter_frame_heap * sizeof( int ) );
     913             :     }
     914             :     n_items_wc_inter_frame_heap = 0;
     915             :     size_wc_inter_frame_heap = 0;
     916             :     location_wc_inter_frame_heap = -1;
     917             : 
     918             : #ifdef MEM_COUNT_DETAILS
     919             :     /* Check, if the .csv file has already been opened */
     920             :     if ( fid_csv_filename == NULL )
     921             :     {
     922             :         fid_csv_filename = fopen( csv_filename, "wb" );
     923             : 
     924             :         if ( fid_csv_filename == NULL )
     925             :         {
     926             :             fprintf( stderr, "\nCannot open %s!\n\n", csv_filename );
     927             :             exit( -1 );
     928             :         }
     929             :     }
     930             :     else
     931             :     {
     932             :         /* reset file */
     933             :         rewind( fid_csv_filename );
     934             :     }
     935             : #endif
     936             : 
     937             :     return;
     938             : }
     939             : 
     940             : /*-------------------------------------------------------------------*
     941             :  * reset_stack()
     942             :  *
     943             :  * Reset stack pointer
     944             :  *--------------------------------------------------------------------*/
     945             : 
     946             : void reset_stack( void )
     947             : {
     948             :     int16_t something;
     949             : 
     950             :     /* initialize/reset stack pointers */
     951             :     ptr_base_stack = &something;
     952             :     ptr_max_stack = ptr_base_stack;
     953             :     ptr_current_stack = ptr_base_stack;
     954             : 
     955             :     return;
     956             : }
     957             : 
     958             : /*-------------------------------------------------------------------*
     959             :  * push_stack()
     960             :  *
     961             :  * Check the current stack pointer and update the maximum stack pointer, if new maximum found.
     962             :  *--------------------------------------------------------------------*/
     963             : 
     964             : int push_stack( const char *filename, const char *fctname )
     965             : {
     966             :     int16_t something;
     967             :     int32_t current_stack_size;
     968             : 
     969             :     ptr_current_stack = &something;
     970             : 
     971             :     (void) *filename; /* to avoid compilation warning */
     972             : 
     973             :     if ( current_calls >= max_num_calls )
     974             :     {
     975             :         /* There is no room for a new record -> reallocate the list */
     976             :         max_num_calls += MAX_NUM_RECORDS_REALLOC_STEP;
     977             :         stack_callers[0] = realloc( stack_callers[0], max_num_calls * sizeof( caller_info ) );
     978             :         stack_callers[1] = realloc( stack_callers[1], max_num_calls * sizeof( caller_info ) );
     979             :     }
     980             : 
     981             :     /* Valid Function Name? */
     982             :     if ( fctname[0] == 0 )
     983             :     { /* No */
     984             :         fprintf( stderr, "Invalid function name for call stack info." );
     985             :         exit( -1 );
     986             :     }
     987             : 
     988             :     /* Save the Name of the Calling Function in the Table */
     989             :     strncpy( stack_callers[0][current_calls].function_name, fctname, MAX_FUNCTION_NAME_LENGTH );
     990             :     stack_callers[0][current_calls].function_name[MAX_FUNCTION_NAME_LENGTH] = 0; /* Nul Terminate */
     991             : 
     992             :     /* Save the Stack Pointer */
     993             :     stack_callers[0][current_calls].stack_ptr = ptr_current_stack;
     994             : 
     995             :     /* Increase the Number of Calls in the List */
     996             :     current_calls++;
     997             : 
     998             :     /* Is this the First Time or the Worst Case? */
     999             :     if ( ptr_current_stack < ptr_max_stack || ptr_max_stack == NULL )
    1000             :     { /* Yes */
    1001             :         /* Save Info about it */
    1002             :         ptr_max_stack = ptr_current_stack;
    1003             : 
    1004             :         /* save the worst-case frame number */
    1005             :         /* current frame number is stored in the variable update_cnt and updated in the function update_wmops() */
    1006             :         wc_stack_frame = update_cnt;
    1007             :         strncpy( location_max_stack, fctname, sizeof( location_max_stack ) - 1 );
    1008             :         location_max_stack[sizeof( location_max_stack ) - 1] = '\0';
    1009             : 
    1010             :         /* Save Call Tree */
    1011             :         memmove( stack_callers[1], stack_callers[0], sizeof( caller_info ) * current_calls );
    1012             : 
    1013             :         /* Terminate the List with 0 (for printing purposes) */
    1014             :         if ( current_calls < max_num_calls )
    1015             :         {
    1016             :             stack_callers[1][current_calls].function_name[0] = 0;
    1017             :         }
    1018             :     }
    1019             : 
    1020             :     /* Check, if This is the New Worst-Case RAM (stack + heap) */
    1021             :     current_stack_size = ( int32_t )( ( ( ptr_base_stack - ptr_current_stack ) * sizeof( int16_t ) ) );
    1022             : 
    1023             :     if ( current_stack_size < 0 )
    1024             :     {
    1025             :         /* prevent negative stack size */
    1026             :         current_stack_size = 0;
    1027             :     }
    1028             : 
    1029             :     if ( current_stack_size + current_heap_size > wc_ram_size )
    1030             :     {
    1031             :         wc_ram_size = current_stack_size + current_heap_size;
    1032             :         wc_ram_frame = update_cnt;
    1033             :     }
    1034             : 
    1035             :     return 0 /* for Now */;
    1036             : }
    1037             : 
    1038             : /*-------------------------------------------------------------------*
    1039             :  * pop_stack()
    1040             :  *
    1041             :  * Remove stack caller entry from the list
    1042             :  *--------------------------------------------------------------------*/
    1043             : 
    1044             : int pop_stack( const char *filename, const char *fctname )
    1045             : {
    1046             :     caller_info *caller_info_ptr;
    1047             : 
    1048             :     (void) *filename; /* to avoid compilation warning */
    1049             : 
    1050             :     /* Decrease the Number of Records */
    1051             :     current_calls--;
    1052             : 
    1053             :     /* Get Pointer to Caller Information */
    1054             :     caller_info_ptr = &stack_callers[0][current_calls];
    1055             : 
    1056             :     /* Check, if the Function Names Match */
    1057             :     if ( strncmp( caller_info_ptr->function_name, fctname, MAX_FUNCTION_NAME_LENGTH ) != 0 )
    1058             :     {
    1059             :         fprintf( stderr, "Invalid usage of pop_stack()" );
    1060             :         exit( -1 );
    1061             :     }
    1062             : 
    1063             :     /* Erase Entry */
    1064             :     caller_info_ptr->function_name[0] = 0;
    1065             : 
    1066             :     /* Retrieve previous stack pointer */
    1067             :     if ( current_calls == 0 )
    1068             :     {
    1069             :         ptr_current_stack = ptr_base_stack;
    1070             :     }
    1071             :     else
    1072             :     {
    1073             :         ptr_current_stack = stack_callers[0][current_calls - 1].stack_ptr;
    1074             :     }
    1075             : 
    1076             :     return 0 /* for Now */;
    1077             : }
    1078             : 
    1079             : #ifdef MEM_COUNT_DETAILS
    1080             : /*-------------------------------------------------------------------*
    1081             :  * print_stack_call_tree()
    1082             :  *
    1083             :  * Print detailed information about worst-case stack usage
    1084             :  *--------------------------------------------------------------------*/
    1085             : 
    1086             : static void print_stack_call_tree( void )
    1087             : {
    1088             :     caller_info *caller_info_ptr;
    1089             :     int call_level;
    1090             :     char fctname[MAX_FUNCTION_NAME_LENGTH + 1];
    1091             : 
    1092             :     fprintf( stdout, "\nList of functions when maximum stack size is reached:\n\n" );
    1093             : 
    1094             :     caller_info_ptr = &stack_callers[1][0];
    1095             :     for ( call_level = 0; call_level < max_num_calls; call_level++ )
    1096             :     {
    1097             :         /* Done? */
    1098             :         if ( caller_info_ptr->function_name[0] == 0 )
    1099             :         {
    1100             :             break;
    1101             :         }
    1102             : 
    1103             :         /* Print Name */
    1104             :         strncpy( fctname, caller_info_ptr->function_name, MAX_FUNCTION_NAME_LENGTH );
    1105             :         strcat( fctname, "()" );
    1106             :         fprintf( stdout, "%-42s", fctname );
    1107             : 
    1108             :         /* Print Stack Usage (Based on Difference) */
    1109             :         if ( call_level != 0 )
    1110             :         {
    1111             :             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] );
    1112             :         }
    1113             :         else
    1114             :         {
    1115             :             fprintf( stdout, "%lu %s\n", ( ( ptr_base_stack - caller_info_ptr->stack_ptr ) * sizeof( int16_t ) ) >> Stat_Cnt_Size, Count_Unit[Stat_Cnt_Size] );
    1116             :         }
    1117             : 
    1118             :         /* Advance */
    1119             :         caller_info_ptr++;
    1120             :     }
    1121             : 
    1122             :     fprintf( stdout, "\n" );
    1123             : 
    1124             :     return;
    1125             : }
    1126             : #endif
    1127             : 
    1128             : 
    1129             : /*-------------------------------------------------------------------*
    1130             :  * mem_alloc()
    1131             :  *
    1132             :  * Creates new record, stores auxiliary information about which function allocated the memory, line number, parameters, etc.
    1133             :  * Finally, it allocates physical memory using malloc()
    1134             :  * The function also updates worst-case heap size and worst-case RAM size
    1135             :  *--------------------------------------------------------------------*/
    1136             : 
    1137             : void *mem_alloc(
    1138             :     const char *func_name,
    1139             :     int func_lineno,
    1140             :     size_t size,
    1141             :     char *size_str /* the first char indicates m-alloc or c-alloc */ )
    1142             : {
    1143             :     int index_record;
    1144             :     int32_t current_stack_size;
    1145             :     unsigned long hash;
    1146             :     allocator_record *ptr_record;
    1147             : 
    1148             :     if ( size == 0 )
    1149             :     {
    1150             :         fprintf( stderr, "Fct=%s, Ln=%i: %s!\n", func_name, func_lineno, "Size of Zero not Supported" );
    1151             :         exit( -1 );
    1152             :     }
    1153             : 
    1154             :     /* Search for an existing record (that has been de-allocated before) */
    1155             :     index_record = 0;
    1156             :     while ( ( ptr_record = get_mem_record( &hash, func_name, func_lineno, size_str, &index_record ) ) != NULL )
    1157             :     {
    1158             :         if ( ptr_record->frame_allocated == -1 )
    1159             :         {
    1160             :             break;
    1161             :         }
    1162             :         else
    1163             :         {
    1164             :             index_record++;
    1165             :         }
    1166             :     }
    1167             : 
    1168             :     /* Create new record */
    1169             :     if ( ptr_record == NULL )
    1170             :     {
    1171             :         if ( Num_Records >= Max_Num_Records )
    1172             :         {
    1173             :             /* There is no room for a new record -> reallocate memory */
    1174             :             Max_Num_Records += MAX_NUM_RECORDS_REALLOC_STEP;
    1175             :             allocation_list = realloc( allocation_list, Max_Num_Records * sizeof( allocator_record ) );
    1176             :         }
    1177             : 
    1178             :         ptr_record = &( allocation_list[Num_Records] );
    1179             : 
    1180             :         /* Initialize new record */
    1181             :         ptr_record->hash = hash;
    1182             :         ptr_record->noccurances = 0;
    1183             :         ptr_record->total_block_size = 0;
    1184             :         ptr_record->total_used_size = 0;
    1185             :         ptr_record->frame_allocated = -1;
    1186             :         ptr_record->OOB_Flag = 0;
    1187             :         ptr_record->wc_heap_size_intra_frame = -1;
    1188             :         ptr_record->wc_heap_size_inter_frame = -1;
    1189             : 
    1190             :         index_record = Num_Records;
    1191             :         Num_Records++;
    1192             :     }
    1193             : 
    1194             :     /* Allocate memory block for the new record, add signature before the beginning and after the memory block and fill it with magic value */
    1195             :     ptr_record->block_ptr = mem_alloc_block( size, size_str );
    1196             : 
    1197             :     if ( ptr_record->block_ptr == NULL )
    1198             :     {
    1199             :         fprintf( stderr, "Fct=%s, Ln=%i: %s!\n", func_name, func_lineno, "Error: Cannot Allocate Memory!" );
    1200             :         exit( -1 );
    1201             :     }
    1202             : 
    1203             :     /* Save all auxiliary information about the memory block */
    1204             :     strncpy( ptr_record->name, func_name, MAX_FUNCTION_NAME_LENGTH );
    1205             :     ptr_record->name[MAX_FUNCTION_NAME_LENGTH] = '\0';
    1206             :     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 */
    1207             :     ptr_record->params[MAX_PARAMS_LENGTH] = '\0';
    1208             :     ptr_record->lineno = func_lineno;
    1209             :     ptr_record->block_size = size;
    1210             :     ptr_record->total_block_size += size;
    1211             : 
    1212             : #ifdef MEM_COUNT_DETAILS
    1213             :     /* Export heap memory allocation record to the .csv file */
    1214             :     fprintf( fid_csv_filename, "A,%ld,%s,%d,%d\n", update_cnt, ptr_record->name, ptr_record->lineno, ptr_record->block_size );
    1215             : #endif
    1216             : 
    1217             :     if ( ptr_record->frame_allocated != -1 )
    1218             :     {
    1219             :         fprintf( stderr, "Fct=%s, Ln=%i: %s!\n", func_name, func_lineno, "Error: Attempt to Allocate the Same Memory Block with Freeing it First!" );
    1220             :         exit( -1 );
    1221             :     }
    1222             : 
    1223             :     ptr_record->frame_allocated = update_cnt; /* Store the current frame number -> later it will be used to determine the total duration */
    1224             : 
    1225             :     /* Update Heap Size in the current frame */
    1226             :     current_heap_size += ptr_record->block_size;
    1227             : 
    1228             :     /* Check, if this is the new Worst-Case RAM (stack + heap) */
    1229             :     current_stack_size = ( int32_t )( ( ( ptr_base_stack - ptr_current_stack ) * sizeof( int16_t ) ) );
    1230             :     if ( current_stack_size + current_heap_size > wc_ram_size )
    1231             :     {
    1232             :         wc_ram_size = current_stack_size + current_heap_size;
    1233             :         wc_ram_frame = update_cnt;
    1234             :     }
    1235             : 
    1236             :     /* Add new entry to the heap allocation call tree */
    1237             :     if ( heap_allocation_call_tree == NULL )
    1238             :     {
    1239             :         fprintf( stderr, "Error: Heap allocation call tree not created!" );
    1240             :         exit( -1 );
    1241             :     }
    1242             : 
    1243             :     /* check, if the maximum size of the call tree has been reached -> resize if so */
    1244             :     if ( heap_allocation_call_tree_size >= heap_allocation_call_tree_max_size )
    1245             :     {
    1246             :         heap_allocation_call_tree_max_size += MAX_NUM_RECORDS_REALLOC_STEP;
    1247             :         heap_allocation_call_tree = (int *) realloc( heap_allocation_call_tree, heap_allocation_call_tree_max_size * sizeof( int ) );
    1248             :     }
    1249             : 
    1250             :     /* push new entry (positive number means push op, neagtive number means pop op; zero index must be converted to 0.01 :-) */
    1251             :     heap_allocation_call_tree[heap_allocation_call_tree_size++] = index_record;
    1252             : 
    1253             :     return ptr_record->block_ptr;
    1254             : }
    1255             : 
    1256             : /*-------------------------------------------------------------------*
    1257             :  * mem_alloc_block()
    1258             :  *
    1259             :  * Physical allocation of memory using malloc(). Appends 'signature' before and after the block,
    1260             :  * pre-fills memory block with magic value
    1261             :  *--------------------------------------------------------------------*/
    1262             : 
    1263             : static void *mem_alloc_block( size_t size, const char *size_str )
    1264             : {
    1265             :     size_t rounded_size;
    1266             :     void *block_ptr;
    1267             :     char *tmp_ptr;
    1268             :     size_t n, f;
    1269             :     int32_t fill_value;
    1270             :     int32_t *ptr32;
    1271             :     int32_t mask, temp;
    1272             : 
    1273             :     /* Round Up Block Size */
    1274             :     rounded_size = ROUND_BLOCK_SIZE( size );
    1275             : 
    1276             :     /* Allocate memory using the standard malloc() by adding room for Signature Values */
    1277             :     block_ptr = malloc( rounded_size + BLOCK_ROUNDING * 2 );
    1278             : 
    1279             :     if ( block_ptr == NULL )
    1280             :     {
    1281             :         return NULL;
    1282             :     }
    1283             : 
    1284             :     /* Add Signature Before the Start of the Block */
    1285             :     ptr32 = (int32_t *) block_ptr;
    1286             :     n = N_32BITS_BLOCKS;
    1287             :     do
    1288             :     {
    1289             :         *ptr32++ = MAGIC_VALUE_OOB;
    1290             :     } while ( --n );
    1291             : 
    1292             :     /* Fill Memory Block with Magic Value or 0 */
    1293             :     fill_value = MAGIC_VALUE_USED;
    1294             :     if ( size_str[0] == 'c' )
    1295             :     {
    1296             :         fill_value = 0x00000000;
    1297             :     }
    1298             :     n = size / sizeof( int32_t );
    1299             :     while ( n-- )
    1300             :     {
    1301             :         *ptr32++ = fill_value;
    1302             :     }
    1303             : 
    1304             :     /* Fill the Reminder of the Memory Block - After Rounding */
    1305             :     n = rounded_size - size;
    1306             :     f = n % sizeof( int32_t );
    1307             :     if ( f != 0 )
    1308             :     {
    1309             :         /* when filling with '0' need to adapt the magic value */
    1310             :         /* shift by [1->24, 2->16, 3->8] */
    1311             :         mask = 0xFFFFFFFF << ( ( sizeof( int32_t ) - f ) * 8 ); /* (1) */
    1312             :         temp = MAGIC_VALUE_OOB & mask;
    1313             :         if ( fill_value != 0x0 )
    1314             :         { /* for malloc merge fill value */
    1315             :             temp += ( ~mask ) & MAGIC_VALUE_USED;
    1316             :         } /* for calloc the code in (1) above already introduces zeros */
    1317             :         *ptr32++ = temp;
    1318             :     }
    1319             :     n /= sizeof( int32_t );
    1320             :     n += N_32BITS_BLOCKS;
    1321             : 
    1322             :     /* Add Signature After the End of Block */
    1323             :     do
    1324             :     {
    1325             :         *ptr32++ = MAGIC_VALUE_OOB;
    1326             :     } while ( --n );
    1327             : 
    1328             :     /* Adjust the Memory Block Pointer (Magic Value Before and After the Memory Block Requested) */
    1329             :     tmp_ptr = (char *) block_ptr;
    1330             :     tmp_ptr += BLOCK_ROUNDING;
    1331             :     block_ptr = (void *) tmp_ptr;
    1332             : 
    1333             :     return block_ptr;
    1334             : }
    1335             : 
    1336             : /*-------------------------------------------------------------------*
    1337             :  * mem_set_usage()
    1338             :  *
    1339             :  * Calculates actual usage of memory block by checking the magic value that was used to pre-fill
    1340             :  * each memory block during its allocation
    1341             :  *--------------------------------------------------------------------*/
    1342             : 
    1343             : static int mem_set_usage( allocator_record *record_ptr )
    1344             : {
    1345             :     int total_bytes_used;
    1346             : 
    1347             :     size_t n;
    1348             :     int32_t *ptr32;
    1349             :     char *ptr8;
    1350             :     size_t total_bytes;
    1351             :     int32_t fill_value;
    1352             : 
    1353             :     fill_value = MAGIC_VALUE_USED;
    1354             :     if ( ( record_ptr->params[0] ) == 'c' )
    1355             :     {
    1356             :         fill_value = 0x00000000;
    1357             :     }
    1358             : 
    1359             :     total_bytes = record_ptr->block_size;
    1360             : 
    1361             :     /* Check 4 bytes at a time */
    1362             :     ptr32 = (int32_t *) record_ptr->block_ptr;
    1363             :     total_bytes_used = 0;
    1364             :     for ( n = total_bytes / sizeof( int32_t ); n > 0; n-- )
    1365             :     {
    1366             :         if ( *ptr32++ != fill_value )
    1367             :         {
    1368             :             total_bytes_used += sizeof( int32_t );
    1369             :         }
    1370             :     }
    1371             : 
    1372             :     /* Check remaining bytes (If Applicable) 1 byte at a time */
    1373             :     ptr8 = (char *) ptr32;
    1374             :     for ( n = total_bytes % sizeof( int32_t ); n > 0; n-- )
    1375             :     {
    1376             :         if ( *ptr8++ != (char) fill_value )
    1377             :         {
    1378             :             total_bytes_used++;
    1379             :         }
    1380             : 
    1381             :         /* Update Value */
    1382             :         fill_value >>= 8;
    1383             :     }
    1384             : 
    1385             :     return total_bytes_used;
    1386             : }
    1387             : 
    1388             : /*-------------------------------------------------------------------*
    1389             :  * mem_check_OOB()
    1390             :  *
    1391             :  * Checks, if out-of-bounds access has occured. This is done by inspecting the 'signature' value
    1392             :  * taht has been added before and after the memory block during its allocation
    1393             :  *--------------------------------------------------------------------*/
    1394             : 
    1395             : static unsigned int mem_check_OOB( allocator_record *record_ptr )
    1396             : {
    1397             :     int32_t *ptr32;
    1398             :     unsigned int OOB_Flag = 0x0;
    1399             :     int32_t mask;
    1400             :     size_t i;
    1401             :     int f;
    1402             : 
    1403             :     ptr32 = (int32_t *) record_ptr->block_ptr - N_32BITS_BLOCKS;
    1404             : 
    1405             :     /* Check the Signature at the Beginning of Memory Block */
    1406             :     i = N_32BITS_BLOCKS;
    1407             :     do
    1408             :     {
    1409             :         if ( *ptr32++ ^ MAGIC_VALUE_OOB )
    1410             :         {
    1411             :             OOB_Flag |= OOB_START;
    1412             :         }
    1413             :     } while ( --i );
    1414             : 
    1415             :     /* Advance to End (Snap to lowest 32 Bits) */
    1416             :     ptr32 += record_ptr->block_size / sizeof( int32_t );
    1417             : 
    1418             :     /* Calculate Unused Space That has been added to get to the rounded Block Size */
    1419             :     i = ROUND_BLOCK_SIZE( record_ptr->block_size ) - record_ptr->block_size;
    1420             : 
    1421             :     /* Partial Check of Signature at the End of Memory Block (for block size that has been rounded) */
    1422             :     f = i % sizeof( int32_t );
    1423             :     if ( f != 0 )
    1424             :     {
    1425             :         mask = 0xFFFFFFFF << ( ( sizeof( int32_t ) - f ) * 8 );
    1426             :         if ( ( *ptr32++ ^ MAGIC_VALUE_OOB ) & mask )
    1427             :         {
    1428             :             OOB_Flag |= OOB_END;
    1429             :         }
    1430             :     }
    1431             : 
    1432             :     /* Full Check of Signature at the End of Memory Block, i.e. all 32 Bits (for the remainder after rounding) */
    1433             :     i /= sizeof( int32_t );
    1434             :     i += N_32BITS_BLOCKS;
    1435             :     do
    1436             :     {
    1437             :         if ( *ptr32++ ^ MAGIC_VALUE_OOB )
    1438             :         {
    1439             :             OOB_Flag |= OOB_END;
    1440             :         }
    1441             :     } while ( --i );
    1442             : 
    1443             :     return OOB_Flag;
    1444             : }
    1445             : 
    1446             : /*-------------------------------------------------------------------*
    1447             :  * malloc_hash()
    1448             :  *
    1449             :  * Calculate hash from function name, line number and malloc size
    1450             :  *--------------------------------------------------------------------*/
    1451             : 
    1452             : static unsigned long malloc_hash( const char *func_name, int func_lineno, char *size_str )
    1453             : {
    1454             :     unsigned long hash = 5381;
    1455             :     const char *ptr_str;
    1456             : 
    1457             :     ptr_str = func_name;
    1458             :     while ( ptr_str != NULL && *ptr_str != '\0' )
    1459             :     {
    1460             :         hash = ( ( hash << 5 ) + hash ) + *ptr_str++; /* hash * 33 + char */
    1461             :     }
    1462             : 
    1463             :     hash = ( ( hash << 5 ) + hash ) + func_lineno; /* hash * 33 + func_lineno */
    1464             : 
    1465             :     ptr_str = size_str;
    1466             :     while ( ptr_str != NULL && *ptr_str != '\0' )
    1467             :     {
    1468             :         hash = ( ( hash << 5 ) + hash ) + *ptr_str++; /* hash * 33 + char */
    1469             :     }
    1470             : 
    1471             :     return hash;
    1472             : }
    1473             : 
    1474             : /*-------------------------------------------------------------------*
    1475             :  * get_mem_record()
    1476             :  *
    1477             :  * Search for memory record in the internal list, return NULL if not found
    1478             :  * Start from index_record
    1479             :  *--------------------------------------------------------------------*/
    1480             : 
    1481             : allocator_record *get_mem_record( unsigned long *hash, const char *func_name, int func_lineno, char *size_str, int *index_record )
    1482             : {
    1483             :     int i;
    1484             : 
    1485             :     if ( *index_record < 0 || *index_record > Num_Records )
    1486             :     {
    1487             :         return NULL;
    1488             :     }
    1489             : 
    1490             :     /* calculate hash */
    1491             :     *hash = malloc_hash( func_name, func_lineno, size_str );
    1492             : 
    1493             :     for ( i = *index_record; i < Num_Records; i++ )
    1494             :     {
    1495             :         /* check, if memory block is not allocated at the moment and the hash matches */
    1496             :         if ( allocation_list[i].block_ptr == NULL && *hash == allocation_list[i].hash )
    1497             :         {
    1498             :             *index_record = i;
    1499             :             return &( allocation_list[i] );
    1500             :         }
    1501             :     }
    1502             : 
    1503             :     /* not found */
    1504             :     *index_record = -1;
    1505             :     return NULL;
    1506             : }
    1507             : 
    1508             : 
    1509             : /*-------------------------------------------------------------------*
    1510             :  * mem_free()
    1511             :  *
    1512             :  * This function de-allocates memory blocks and frees physical memory with free().
    1513             :  * It also updates the actual and average usage of memory blocks.
    1514             :  *
    1515             :  * Note: The record is not removed from the list and may be reused later on in mem_alloc()!
    1516             :  *--------------------------------------------------------------------*/
    1517             : 
    1518             : void mem_free( const char *func_name, int func_lineno, void *ptr )
    1519             : {
    1520             :     int i, index_record;
    1521             :     char *tmp_ptr;
    1522             :     allocator_record *ptr_record;
    1523             : 
    1524             :     /* Search for the Block Pointer in the List */
    1525             :     ptr_record = NULL;
    1526             :     index_record = -1;
    1527             :     for ( i = 0; i < Num_Records; i++ )
    1528             :     {
    1529             :         if ( ptr == allocation_list[i].block_ptr )
    1530             :         { /* Yes, Found it */
    1531             :             ptr_record = &( allocation_list[i] );
    1532             :             index_record = i;
    1533             :             break;
    1534             :         }
    1535             :     }
    1536             : 
    1537             :     if ( ptr_record == NULL )
    1538             :     {
    1539             :         fprintf( stderr, "Fct=%s, Ln=%i: %s!\n", func_name, func_lineno, "Error: Unable to Find Record Corresponding to the Allocated Memory Block!" );
    1540             :         exit( -1 );
    1541             :     }
    1542             : 
    1543             :     /* Update the Heap Size */
    1544             :     current_heap_size -= ptr_record->block_size;
    1545             : 
    1546             :     /* Calculate the Actual Usage of the Memory Block (Look for Signature) */
    1547             :     ptr_record->total_used_size += mem_set_usage( ptr_record );
    1548             : 
    1549             :     /* Check, if Out-Of-Bounds Access has been Detected */
    1550             :     ptr_record->OOB_Flag = mem_check_OOB( ptr_record );
    1551             : 
    1552             : #ifdef MEM_COUNT_DETAILS
    1553             :     /* Export heap memory de-allocation record to the .csv file */
    1554             :     fprintf( fid_csv_filename, "D,%ld,%s,%d,%d\n", update_cnt, ptr_record->name, ptr_record->lineno, ptr_record->block_size );
    1555             : #endif
    1556             : 
    1557             :     /* De-Allocate Memory Block */
    1558             :     tmp_ptr = (char *) ptr;
    1559             :     tmp_ptr -= BLOCK_ROUNDING;
    1560             :     ptr = (void *) tmp_ptr;
    1561             :     free( ptr );
    1562             : 
    1563             :     /* Add new entry to the heap allocation call tree */
    1564             :     if ( heap_allocation_call_tree == NULL )
    1565             :     {
    1566             :         fprintf( stderr, "Error: Heap allocation call tree not created!" );
    1567             :         exit( -1 );
    1568             :     }
    1569             : 
    1570             :     /* check, if the maximum size of the call tree has been reached -> resize if so */
    1571             :     if ( heap_allocation_call_tree_size >= heap_allocation_call_tree_max_size )
    1572             :     {
    1573             :         heap_allocation_call_tree_max_size += MAX_NUM_RECORDS_REALLOC_STEP;
    1574             :         heap_allocation_call_tree = (int *) realloc( heap_allocation_call_tree, heap_allocation_call_tree_max_size * sizeof( int ) );
    1575             :     }
    1576             : 
    1577             :     heap_allocation_call_tree[heap_allocation_call_tree_size++] = -index_record;
    1578             : 
    1579             :     /* Reset memory block pointer (this is checked when updating wc intra-frame and inter-frame memory) */
    1580             :     ptr_record->block_ptr = NULL;
    1581             : 
    1582             :     return;
    1583             : }
    1584             : 
    1585             : 
    1586             : /*-------------------------------------------------------------------*
    1587             :  * update_mem()
    1588             :  *
    1589             :  * This function updates the worst-case intra-frame memory and the worst-case inter-frame memory.
    1590             :  *--------------------------------------------------------------------*/
    1591             : 
    1592             : void update_mem( void )
    1593             : {
    1594             :     int i, j, flag_alloc = -1, i_record;
    1595             :     int size_current_intra_frame_heap;
    1596             :     int *list_current_intra_frame_heap = NULL, n_items_current_intra_frame_heap;
    1597             :     allocator_record *ptr_record;
    1598             : 
    1599             :     /* process the heap allocation call tree and prepare lists of intra-frame and inter-frame heap memory blocks for this frame */
    1600             :     n_items_current_intra_frame_heap = 0;
    1601             :     size_current_intra_frame_heap = 0;
    1602             :     for ( i = 0; i < heap_allocation_call_tree_size; i++ )
    1603             :     {
    1604             :         /* get the record */
    1605             :         i_record = heap_allocation_call_tree[i];
    1606             : 
    1607             :         if ( i_record > 0 )
    1608             :         {
    1609             :             flag_alloc = 1;
    1610             :         }
    1611             :         else if ( i_record < 0 )
    1612             :         {
    1613             :             flag_alloc = 0;
    1614             :             i_record = -i_record;
    1615             :         }
    1616             :         ptr_record = &( allocation_list[i_record] );
    1617             : 
    1618             :         if ( ptr_record->frame_allocated == update_cnt && ptr_record->block_ptr == NULL )
    1619             :         {
    1620             :             /* intra-frame heap memory */
    1621             :             if ( list_current_intra_frame_heap == NULL )
    1622             :             {
    1623             :                 list_current_intra_frame_heap = (int *) malloc( heap_allocation_call_tree_size * sizeof( int ) );
    1624             :                 memset( list_current_intra_frame_heap, -1, heap_allocation_call_tree_size * sizeof( int ) );
    1625             :             }
    1626             : 
    1627             :             /* zero index doesn't have sign to determine whether it's allocated or de-allocated -> we need to search the list */
    1628             :             if ( i_record == 0 )
    1629             :             {
    1630             :                 flag_alloc = 1;
    1631             :                 for ( j = 0; j < n_items_current_intra_frame_heap; j++ )
    1632             :                 {
    1633             :                     if ( list_current_intra_frame_heap[j] == i_record )
    1634             :                     {
    1635             :                         flag_alloc = 0;
    1636             :                         break;
    1637             :                     }
    1638             :                 }
    1639             :             }
    1640             : 
    1641             :             if ( flag_alloc )
    1642             :             {
    1643             :                 /* add to list */
    1644             :                 list_current_intra_frame_heap[n_items_current_intra_frame_heap++] = i_record;
    1645             :                 size_current_intra_frame_heap += ptr_record->block_size;
    1646             : 
    1647             :                 /* no need to re-size the list -> the initially allocated size should be large enough */
    1648             :             }
    1649             :             else
    1650             :             {
    1651             :                 /* remove from list */
    1652             :                 for ( j = 0; j < n_items_current_intra_frame_heap; j++ )
    1653             :                 {
    1654             :                     if ( list_current_intra_frame_heap[j] == i_record )
    1655             :                     {
    1656             :                         break;
    1657             :                     }
    1658             :                 }
    1659             :                 memmove( &list_current_intra_frame_heap[j], &list_current_intra_frame_heap[j + 1], ( n_items_current_intra_frame_heap - j ) * sizeof( int ) );
    1660             :                 n_items_current_intra_frame_heap--;
    1661             :                 size_current_intra_frame_heap -= ptr_record->block_size;
    1662             : 
    1663             :                 /* reset block size */
    1664             :                 ptr_record->frame_allocated = -1;
    1665             :                 ptr_record->block_size = 0;
    1666             :             }
    1667             :         }
    1668             :         else
    1669             :         {
    1670             :             /* inter-frame heap memory */
    1671             : 
    1672             :             /* zero index doesn't have sign to determine whether it's  allocated or de-allocated -> we need to search the list */
    1673             :             if ( i_record == 0 )
    1674             :             {
    1675             :                 flag_alloc = 1;
    1676             :                 for ( j = 0; j < n_items_current_inter_frame_heap; j++ )
    1677             :                 {
    1678             :                     if ( list_current_inter_frame_heap[j] == i_record )
    1679             :                     {
    1680             :                         flag_alloc = 0;
    1681             :                         break;
    1682             :                     }
    1683             :                 }
    1684             :             }
    1685             : 
    1686             :             if ( flag_alloc )
    1687             :             {
    1688             :                 /* add to list */
    1689             :                 if ( n_items_current_inter_frame_heap >= max_items_current_inter_frame_heap )
    1690             :                 {
    1691             :                     /* resize list, if needed */
    1692             :                     max_items_current_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;
    1693             :                     list_current_inter_frame_heap = realloc( list_current_inter_frame_heap, max_items_current_inter_frame_heap * sizeof( int ) );
    1694             :                 }
    1695             : 
    1696             :                 list_current_inter_frame_heap[n_items_current_inter_frame_heap++] = i_record;
    1697             :                 size_current_inter_frame_heap += ptr_record->block_size;
    1698             :             }
    1699             :             else
    1700             :             {
    1701             :                 /* remove from list */
    1702             :                 for ( j = 0; j < n_items_current_inter_frame_heap; j++ )
    1703             :                 {
    1704             :                     if ( list_current_inter_frame_heap[j] == i_record )
    1705             :                     {
    1706             :                         break;
    1707             :                     }
    1708             :                 }
    1709             :                 memmove( &list_current_inter_frame_heap[j], &list_current_inter_frame_heap[j + 1], ( n_items_current_inter_frame_heap - j ) * sizeof( int ) );
    1710             :                 n_items_current_inter_frame_heap--;
    1711             :                 size_current_inter_frame_heap -= ptr_record->block_size;
    1712             : 
    1713             :                 /* reset block size */
    1714             :                 ptr_record->frame_allocated = -1;
    1715             :                 ptr_record->block_size = 0;
    1716             :             }
    1717             :         }
    1718             :     }
    1719             : 
    1720             :     /* check, if this is the new worst-case for intra-frame heap memory */
    1721             :     if ( size_current_intra_frame_heap > size_wc_intra_frame_heap )
    1722             :     {
    1723             :         if ( n_items_current_intra_frame_heap >= max_items_wc_intra_frame_heap )
    1724             :         {
    1725             :             /* resize the list, if needed */
    1726             :             max_items_wc_intra_frame_heap = n_items_current_intra_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;
    1727             :             list_wc_intra_frame_heap = realloc( list_wc_intra_frame_heap, max_items_wc_intra_frame_heap * sizeof( int ) );
    1728             :         }
    1729             : 
    1730             :         /* copy current-frame list to worst-case list */
    1731             :         memmove( list_wc_intra_frame_heap, list_current_intra_frame_heap, n_items_current_intra_frame_heap * sizeof( int ) );
    1732             :         n_items_wc_intra_frame_heap = n_items_current_intra_frame_heap;
    1733             :         size_wc_intra_frame_heap = size_current_intra_frame_heap;
    1734             :         location_wc_intra_frame_heap = update_cnt;
    1735             : 
    1736             :         /* update the wc numbers in all individual records */
    1737             :         for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )
    1738             :         {
    1739             :             i_record = list_wc_intra_frame_heap[i];
    1740             :             ptr_record = &( allocation_list[i_record] );
    1741             :             ptr_record->wc_heap_size_intra_frame = ptr_record->block_size;
    1742             :         }
    1743             :     }
    1744             : 
    1745             :     /* check, if this is the new worst-case for inter-frame heap memory */
    1746             :     if ( size_current_inter_frame_heap > size_wc_inter_frame_heap )
    1747             :     {
    1748             :         if ( n_items_current_inter_frame_heap >= max_items_wc_inter_frame_heap )
    1749             :         {
    1750             :             /* resize list, if needed */
    1751             :             max_items_wc_inter_frame_heap = n_items_current_inter_frame_heap + MAX_NUM_RECORDS_REALLOC_STEP;
    1752             :             list_wc_inter_frame_heap = realloc( list_wc_inter_frame_heap, max_items_wc_inter_frame_heap * sizeof( int ) );
    1753             :         }
    1754             : 
    1755             :         /* copy current-frame list to worst-case list */
    1756             :         memmove( list_wc_inter_frame_heap, list_current_inter_frame_heap, n_items_current_inter_frame_heap * sizeof( int ) );
    1757             :         n_items_wc_inter_frame_heap = n_items_current_inter_frame_heap;
    1758             :         size_wc_inter_frame_heap = size_current_inter_frame_heap;
    1759             :         location_wc_inter_frame_heap = update_cnt;
    1760             : 
    1761             :         /* update the wc numbers in all individual records */
    1762             :         for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )
    1763             :         {
    1764             :             i_record = list_wc_inter_frame_heap[i];
    1765             :             ptr_record = &( allocation_list[i_record] );
    1766             :             ptr_record->wc_heap_size_inter_frame = ptr_record->block_size;
    1767             :         }
    1768             :     }
    1769             : 
    1770             :     /* reset heap allocation call tree */
    1771             :     heap_allocation_call_tree_size = 0;
    1772             : 
    1773             :     /* de-allocate list of intra-frame heap memory blocks in the current fraeme - it's needed only inside this function */
    1774             :     if ( list_current_intra_frame_heap )
    1775             :     {
    1776             :         free( list_current_intra_frame_heap );
    1777             :     }
    1778             : 
    1779             :     return;
    1780             : }
    1781             : 
    1782             : #ifdef MEM_COUNT_DETAILS
    1783             : /*-------------------------------------------------------------------*
    1784             :  * subst()
    1785             :  *
    1786             :  * Substitute character in string
    1787             :  *--------------------------------------------------------------------*/
    1788             : 
    1789             : static void subst( char *s, char from, char to )
    1790             : {
    1791             :     while ( *s == from )
    1792             :     {
    1793             :         *s++ = to;
    1794             :     }
    1795             : 
    1796             :     return;
    1797             : }
    1798             : 
    1799             : 
    1800             : /*-------------------------------------------------------------------*
    1801             :  * mem_count_summary()
    1802             :  *
    1803             :  * Print detailed (per-item) information about heap memory usage
    1804             :  *--------------------------------------------------------------------*/
    1805             : 
    1806             : static void mem_count_summary( void )
    1807             : {
    1808             :     int i, j, index, index_record;
    1809             :     size_t length;
    1810             :     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];
    1811             :     allocator_record *ptr_record, *ptr;
    1812             : 
    1813             :     /* Prepare format string */
    1814             :     sprintf( format_str, "%%-%d.%ds %%5.5s %%6.6s %%-%d.%ds %%20.20s %%6.6s ", 50, 50, 50, 50 );
    1815             : 
    1816             :     if ( n_items_wc_intra_frame_heap > 0 )
    1817             :     {
    1818             :         /* Intra-Frame Heap Size */
    1819             :         fprintf( stdout, "\nList of memory blocks when maximum intra-frame heap size is reached:\n\n" );
    1820             : 
    1821             :         /* Find duplicate records (same hash and worst-case heap size) */
    1822             :         for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )
    1823             :         {
    1824             :             index_record = list_wc_intra_frame_heap[i];
    1825             :             if ( index_record == -1 )
    1826             :             {
    1827             :                 continue;
    1828             :             }
    1829             : 
    1830             :             ptr_record = &( allocation_list[index_record] );
    1831             :             for ( j = i + 1; j < n_items_wc_intra_frame_heap; j++ )
    1832             :             {
    1833             :                 index = list_wc_intra_frame_heap[j];
    1834             :                 if ( index == -1 )
    1835             :                 {
    1836             :                     continue;
    1837             :                 }
    1838             :                 ptr = &( allocation_list[index] );
    1839             : 
    1840             :                 if ( ptr->hash == ptr_record->hash && ptr->wc_heap_size_intra_frame == ptr_record->wc_heap_size_intra_frame )
    1841             :                 {
    1842             :                     ptr_record->noccurances++;
    1843             :                     list_wc_intra_frame_heap[j] = -1;
    1844             :                 }
    1845             :             }
    1846             :         }
    1847             : 
    1848             :         /* Print Header */
    1849             :         sprintf( buf, format_str, "Function Name", "Line", "Type", "Function Parameters", "Maximum Size", "Usage" );
    1850             :         puts( buf );
    1851             :         length = strlen( buf );
    1852             :         sprintf( buf, "%0*d\n", (int) length - 1, 0 );
    1853             :         subst( buf, '0', '-' );
    1854             :         puts( buf );
    1855             : 
    1856             :         for ( i = 0; i < n_items_wc_intra_frame_heap; i++ )
    1857             :         {
    1858             :             index_record = list_wc_intra_frame_heap[i];
    1859             : 
    1860             :             if ( index_record != -1 )
    1861             :             {
    1862             :                 /* get the record */
    1863             :                 ptr_record = &( allocation_list[index_record] );
    1864             : 
    1865             :                 /* prepare information strings */
    1866             :                 strncpy( name_str, ptr_record->name, MAX_FUNCTION_NAME_LENGTH );
    1867             :                 strcat( name_str, "()" );
    1868             :                 name_str[MAX_FUNCTION_NAME_LENGTH] = '\0';
    1869             :                 strncpy( parms_str, &( ptr_record->params[2] ), MAX_PARAMS_LENGTH );
    1870             :                 parms_str[MAX_PARAMS_LENGTH] = '\0';
    1871             : 
    1872             :                 if ( ptr_record->params[0] == 'm' )
    1873             :                 {
    1874             :                     strcpy( type_str, "malloc" );
    1875             :                 }
    1876             :                 else
    1877             :                 {
    1878             :                     strcpy( type_str, "calloc" );
    1879             :                 }
    1880             : 
    1881             :                 sprintf( line_str, "%d", ptr_record->lineno );
    1882             : 
    1883             :                 /* prepare average usage & memory size strings */
    1884             :                 sprintf( usage_str, "%d%%", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 1 ) ) * 100.0f ) );
    1885             : 
    1886             :                 if ( ptr_record->noccurances > 1 )
    1887             :                 {
    1888             :                     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] );
    1889             :                 }
    1890             :                 else
    1891             :                 {
    1892             :                     sprintf( size_str, "%d %s", (int) ( ptr_record->wc_heap_size_intra_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );
    1893             :                 }
    1894             : 
    1895             :                 sprintf( buf, format_str, name_str, line_str, type_str, parms_str, size_str, usage_str );
    1896             :                 puts( buf );
    1897             :             }
    1898             :         }
    1899             : 
    1900             :         fprintf( stdout, "\n" );
    1901             :     }
    1902             : 
    1903             :     if ( n_items_wc_inter_frame_heap > 0 )
    1904             :     {
    1905             :         /* Inter-Frame Heap Size */
    1906             :         fprintf( stdout, "\nList of memory blocks when maximum inter-frame heap size is reached:\n\n" );
    1907             : 
    1908             :         /* Find duplicate records (same hash and worst-case heap size) */
    1909             :         for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )
    1910             :         {
    1911             :             index_record = list_wc_inter_frame_heap[i];
    1912             :             if ( index_record == -1 )
    1913             :             {
    1914             :                 continue;
    1915             :             }
    1916             :             ptr_record = &( allocation_list[index_record] );
    1917             :             ptr_record->noccurances = 1; /* reset the counter as some blocks may have been both, intra-frame and inter-frame */
    1918             :             for ( j = i + 1; j < n_items_wc_inter_frame_heap; j++ )
    1919             :             {
    1920             :                 index = list_wc_inter_frame_heap[j];
    1921             :                 if ( index == -1 )
    1922             :                 {
    1923             :                     continue;
    1924             :                 }
    1925             :                 ptr = &( allocation_list[index] );
    1926             : 
    1927             :                 if ( ptr->hash == ptr_record->hash && ptr->wc_heap_size_inter_frame == ptr_record->wc_heap_size_inter_frame )
    1928             :                 {
    1929             :                     ptr_record->noccurances++;
    1930             :                     list_wc_inter_frame_heap[j] = -1;
    1931             :                 }
    1932             :             }
    1933             :         }
    1934             : 
    1935             :         /* Print Header */
    1936             :         sprintf( buf, format_str, "Function Name", "Line", "Type", "Function Parameters", "Memory Size", "Usage" );
    1937             :         puts( buf );
    1938             :         length = strlen( buf );
    1939             :         sprintf( buf, "%0*d\n", (int) length - 1, 0 );
    1940             :         subst( buf, '0', '-' );
    1941             :         puts( buf );
    1942             : 
    1943             :         for ( i = 0; i < n_items_wc_inter_frame_heap; i++ )
    1944             :         {
    1945             :             index_record = list_wc_inter_frame_heap[i];
    1946             : 
    1947             :             if ( index_record != -1 )
    1948             :             {
    1949             :                 /* get the record */
    1950             :                 ptr_record = &( allocation_list[index_record] );
    1951             : 
    1952             :                 /* prepare information strings */
    1953             :                 strncpy( name_str, ptr_record->name, MAX_FUNCTION_NAME_LENGTH );
    1954             :                 strcat( name_str, "()" );
    1955             :                 name_str[MAX_FUNCTION_NAME_LENGTH] = '\0';
    1956             :                 strncpy( parms_str, &( ptr_record->params[2] ), MAX_PARAMS_LENGTH );
    1957             :                 parms_str[MAX_PARAMS_LENGTH] = '\0';
    1958             : 
    1959             :                 if ( ptr_record->params[0] == 'm' )
    1960             :                 {
    1961             :                     strcpy( type_str, "malloc" );
    1962             :                 }
    1963             :                 else
    1964             :                 {
    1965             :                     strcpy( type_str, "calloc" );
    1966             :                 }
    1967             : 
    1968             :                 sprintf( line_str, "%d", ptr_record->lineno );
    1969             : 
    1970             :                 /* prepare average usage & memory size strings */
    1971             :                 sprintf( usage_str, "%d%%", (int) ( ( (float) ptr_record->total_used_size / ( ptr_record->total_block_size + 0.1f ) ) * 100.0f + 0.5f ) );
    1972             : 
    1973             :                 if ( ptr_record->noccurances > 1 )
    1974             :                 {
    1975             :                     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] );
    1976             :                 }
    1977             :                 else
    1978             :                 {
    1979             :                     sprintf( size_str, "%d %s", (int) ( ptr_record->wc_heap_size_inter_frame >> Stat_Cnt_Size ), Count_Unit[Stat_Cnt_Size] );
    1980             :                 }
    1981             : 
    1982             :                 sprintf( buf, format_str, name_str, line_str, type_str, parms_str, size_str, usage_str );
    1983             :                 puts( buf );
    1984             :             }
    1985             :         }
    1986             : 
    1987             :         fprintf( stdout, "\n" );
    1988             :     }
    1989             : 
    1990             :     return;
    1991             : }
    1992             : 
    1993             : #endif
    1994             : 
    1995             : /*-------------------------------------------------------------------*
    1996             :  * print_mem()
    1997             :  *
    1998             :  * Print information about ROM and RAM memory usage
    1999             :  *--------------------------------------------------------------------*/
    2000             : 
    2001             : void print_mem( ROM_Size_Lookup_Table Const_Data_PROM_Table[] )
    2002             : {
    2003             :     int i, nElem;
    2004             : 
    2005             :     fprintf( stdout, "\n\n --- Memory usage ---  \n\n" );
    2006             : 
    2007             :     if ( Const_Data_PROM_Table != NULL )
    2008             :     {
    2009             :         nElem = 0;
    2010             :         while ( strcmp( Const_Data_PROM_Table[nElem].file_spec, "" ) != 0 )
    2011             :             nElem++;
    2012             : 
    2013             :         for ( i = 0; i < nElem; i++ )
    2014             :         {
    2015             :             if ( Stat_Cnt_Size > 0 )
    2016             :             {
    2017             :                 /* words */
    2018             :                 fprintf( stdout, "Program ROM size (%s): %d words\n", Const_Data_PROM_Table[i].file_spec, Const_Data_PROM_Table[i].PROM_size );
    2019             :             }
    2020             :             else
    2021             :             {
    2022             :                 /* bytes (here, we assume that each instruction takes PROM_INST_SIZE bits of the PROM memory) */
    2023             :                 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 ) );
    2024             :             }
    2025             :         }
    2026             : 
    2027             :         for ( i = 0; i < nElem; i++ )
    2028             :         {
    2029             :             if ( Const_Data_PROM_Table[i].Get_Const_Data_Size_Func == NULL )
    2030             :             {
    2031             :                 fprintf( stdout, "Error: Cannot retrieve or calculate Table ROM size of (%s)!\n", Const_Data_PROM_Table[i].file_spec );
    2032             :             }
    2033             : 
    2034             :             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] );
    2035             :         }
    2036             :     }
    2037             :     else
    2038             :     {
    2039             :         fprintf( stdout, "Program ROM size: not available\n" );
    2040             :         fprintf( stdout, "Table ROM (const data) size: not available\n" );
    2041             :     }
    2042             : 
    2043             :     if ( wc_ram_size > 0 )
    2044             :     {
    2045             :         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 );
    2046             :     }
    2047             :     else
    2048             :     {
    2049             :         fprintf( stdout, "Maximum RAM (stack + heap) size: not available\n" );
    2050             :     }
    2051             : 
    2052             :     /* check, if the stack is empty */
    2053             :     if ( ptr_current_stack != ptr_base_stack )
    2054             :     {
    2055             :         fprintf( stderr, "Warning: Stack is not empty.\n" );
    2056             :     }
    2057             : 
    2058             :     if ( ptr_base_stack - ptr_max_stack > 0 )
    2059             :     {
    2060             :         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],
    2061             :                  wc_stack_frame );
    2062             :     }
    2063             :     else
    2064             :     {
    2065             :         fprintf( stdout, "Maximum stack size: not available\n" );
    2066             :     }
    2067             : 
    2068             :     /* last update of intra-frame memory and inter-frame memory, if needed */
    2069             :     if ( heap_allocation_call_tree_size > 0 )
    2070             :     {
    2071             :         update_mem();
    2072             :     }
    2073             : 
    2074             :     /* check, if all memory blocks have been deallocated (freed) */
    2075             :     for ( i = 0; i < Num_Records; i++ )
    2076             :     {
    2077             :         if ( allocation_list[i].block_ptr != NULL )
    2078             :         {
    2079             :             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()!" );
    2080             :             exit( -1 );
    2081             :         }
    2082             :     }
    2083             : 
    2084             :     if ( n_items_wc_intra_frame_heap > 0 )
    2085             :     {
    2086             :         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 );
    2087             :     }
    2088             :     else
    2089             :     {
    2090             :         fprintf( stdout, "Maximum intra-frame heap size: 0\n" );
    2091             :     }
    2092             : 
    2093             :     if ( n_items_wc_inter_frame_heap > 0 )
    2094             :     {
    2095             :         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 );
    2096             :     }
    2097             :     else
    2098             :     {
    2099             :         fprintf( stdout, "Maximum inter-frame heap size: 0\n" );
    2100             :     }
    2101             : 
    2102             : #ifdef MEM_COUNT_DETAILS
    2103             :     /* Print detailed information about worst-case stack usage */
    2104             :     if ( ptr_base_stack - ptr_max_stack > 0 )
    2105             :     {
    2106             :         print_stack_call_tree();
    2107             :     }
    2108             : 
    2109             :     /* Print detailed information about worst-case heap usage */
    2110             :     mem_count_summary();
    2111             : #endif
    2112             : 
    2113             :     if ( Stat_Cnt_Size > 0 )
    2114             :     {
    2115             :         /* words */
    2116             :         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 );
    2117             :     }
    2118             :     else
    2119             :     {
    2120             :         /* bytes */
    2121             :         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 );
    2122             :     }
    2123             :     fprintf( stdout, "Note: The Data ROM size is calculated using the sizeof(type) built-in function\n" );
    2124             : 
    2125             :     if ( n_items_wc_intra_frame_heap > 0 )
    2126             :     {
    2127             :         fprintf( stdout, "Intra-frame heap memory is allocated and de-allocated in the same frame\n" );
    2128             :     }
    2129             : 
    2130             :     /* De-allocate list of heap memory blocks */
    2131             :     if ( allocation_list != NULL )
    2132             :     {
    2133             :         free( allocation_list );
    2134             :     }
    2135             : 
    2136             :     /* De-allocate list of stack records */
    2137             :     if ( stack_callers[0] != NULL )
    2138             :     {
    2139             :         free( stack_callers[0] );
    2140             :     }
    2141             : 
    2142             :     if ( stack_callers[1] != NULL )
    2143             :     {
    2144             :         free( stack_callers[1] );
    2145             :     }
    2146             : 
    2147             :     /* De-allocate heap allocation call tree */
    2148             :     if ( heap_allocation_call_tree != NULL )
    2149             :     {
    2150             :         free( heap_allocation_call_tree );
    2151             :     }
    2152             : 
    2153             :     /* De-allocate intra-frame and inter-frame heap lists */
    2154             :     if ( list_wc_intra_frame_heap != NULL )
    2155             :     {
    2156             :         free( list_wc_intra_frame_heap );
    2157             :     }
    2158             : 
    2159             :     if ( list_current_inter_frame_heap != NULL )
    2160             :     {
    2161             :         free( list_current_inter_frame_heap );
    2162             :     }
    2163             : 
    2164             :     if ( list_wc_inter_frame_heap != NULL )
    2165             :     {
    2166             :         free( list_wc_inter_frame_heap );
    2167             :     }
    2168             : 
    2169             : #ifdef MEM_COUNT_DETAILS
    2170             :     if ( fid_csv_filename != NULL )
    2171             :     {
    2172             :         fclose( fid_csv_filename );
    2173             :     }
    2174             : #endif
    2175             : 
    2176             :     return;
    2177             : }
    2178             : 
    2179             : #endif /* WMOPS */
    2180             : 
    2181             : #ifdef CONTROL_CODE_OPS
    2182             : 
    2183             : int LT_16( short var1, short var2 )
    2184             : {
    2185  8912768759 :     int F_ret = 0;
    2186             : 
    2187  8912768759 :     if ( var1 < var2 )
    2188             :     {
    2189  3171492693 :         F_ret = 1;
    2190             :     }
    2191             : #ifdef WMOPS
    2192             :     multiCounter[currCounter].LT_16++;
    2193             : #endif
    2194  8912768759 :     return F_ret;
    2195             : }
    2196             : 
    2197             : int GT_16( short var1, short var2 )
    2198             : {
    2199  5369280904 :     int F_ret = 0;
    2200             : 
    2201  5369280904 :     if ( var1 > var2 )
    2202             :     {
    2203  1709890519 :         F_ret = 1;
    2204             :     }
    2205             : #ifdef WMOPS
    2206             :     multiCounter[currCounter].GT_16++;
    2207             : #endif
    2208  5369280904 :     return F_ret;
    2209             : }
    2210             : 
    2211             : int LE_16( short var1, short var2 )
    2212             : {
    2213   324545841 :     int F_ret = 0;
    2214             : 
    2215   324545841 :     if ( var1 <= var2 )
    2216             :     {
    2217   164558047 :         F_ret = 1;
    2218             :     }
    2219             : #ifdef WMOPS
    2220             :     multiCounter[currCounter].LE_16++;
    2221             : #endif
    2222   324545841 :     return F_ret;
    2223             : }
    2224             : 
    2225             : int GE_16( short var1, short var2 )
    2226             : {
    2227  2643831754 :     int F_ret = 0;
    2228             : 
    2229  2643831754 :     if ( var1 >= var2 )
    2230             :     {
    2231   530239225 :         F_ret = 1;
    2232             :     }
    2233             : #ifdef WMOPS
    2234             :     multiCounter[currCounter].GE_16++;
    2235             : #endif
    2236  2643831754 :     return F_ret;
    2237             : }
    2238             : 
    2239             : int EQ_16( short var1, short var2 )
    2240             : {
    2241  5049149226 :     int F_ret = 0;
    2242             : 
    2243  5049149226 :     if ( var1 == var2 )
    2244             :     {
    2245  1015884339 :         F_ret = 1;
    2246             :     }
    2247             : #ifdef WMOPS
    2248             :     multiCounter[currCounter].EQ_16++;
    2249             : #endif
    2250  5049149226 :     return F_ret;
    2251             : }
    2252             : 
    2253             : int NE_16( short var1, short var2 )
    2254             : {
    2255  1898552358 :     int F_ret = 0;
    2256             : 
    2257  1898552358 :     if ( var1 != var2 )
    2258             :     {
    2259  1013936887 :         F_ret = 1;
    2260             :     }
    2261             : #ifdef WMOPS
    2262             :     multiCounter[currCounter].NE_16++;
    2263             : #endif
    2264  1898552358 :     return F_ret;
    2265             : }
    2266             : 
    2267             : int LT_32( int L_var1, int L_var2 )
    2268             : {
    2269  7065742668 :     int F_ret = 0;
    2270             : 
    2271  7065742668 :     if ( L_var1 < L_var2 )
    2272             :     {
    2273  1774396084 :         F_ret = 1;
    2274             :     }
    2275             : #ifdef WMOPS
    2276             :     multiCounter[currCounter].LT_32++;
    2277             : #endif
    2278  7065742668 :     return F_ret;
    2279             : }
    2280             : 
    2281             : int GT_32( int L_var1, int L_var2 )
    2282             : {
    2283 14446730941 :     int F_ret = 0;
    2284             : 
    2285 14446730941 :     if ( L_var1 > L_var2 )
    2286             :     {
    2287  1361602681 :         F_ret = 1;
    2288             :     }
    2289             : #ifdef WMOPS
    2290             :     multiCounter[currCounter].GT_32++;
    2291             : #endif
    2292 14446730941 :     return F_ret;
    2293             : }
    2294             : 
    2295             : int LE_32( int L_var1, int L_var2 )
    2296             : {
    2297   672106519 :     int F_ret = 0;
    2298             : 
    2299   672106519 :     if ( L_var1 <= L_var2 )
    2300             :     {
    2301   406715372 :         F_ret = 1;
    2302             :     }
    2303             : #ifdef WMOPS
    2304             :     multiCounter[currCounter].LE_32++;
    2305             : #endif
    2306   672106519 :     return F_ret;
    2307             : }
    2308             : 
    2309             : int GE_32( int L_var1, int L_var2 )
    2310             : {
    2311   554423689 :     int F_ret = 0;
    2312             : 
    2313   554423689 :     if ( L_var1 >= L_var2 )
    2314             :     {
    2315   188774029 :         F_ret = 1;
    2316             :     }
    2317             : #ifdef WMOPS
    2318             :     multiCounter[currCounter].GE_32++;
    2319             : #endif
    2320   554423689 :     return F_ret;
    2321             : }
    2322             : 
    2323             : int EQ_32( int L_var1, int L_var2 )
    2324             : {
    2325  3194153415 :     int F_ret = 0;
    2326             : 
    2327  3194153415 :     if ( L_var1 == L_var2 )
    2328             :     {
    2329   278776691 :         F_ret = 1;
    2330             :     }
    2331             : #ifdef WMOPS
    2332             :     multiCounter[currCounter].EQ_32++;
    2333             : #endif
    2334  3194153415 :     return F_ret;
    2335             : }
    2336             : 
    2337             : int NE_32( int L_var1, int L_var2 )
    2338             : {
    2339   436669955 :     int F_ret = 0;
    2340             : 
    2341   436669955 :     if ( L_var1 != L_var2 )
    2342             :     {
    2343    51266453 :         F_ret = 1;
    2344             :     }
    2345             : #ifdef WMOPS
    2346             :     multiCounter[currCounter].NE_32++;
    2347             : #endif
    2348   436669955 :     return F_ret;
    2349             : }
    2350             : 
    2351             : int LT_64( long long int L64_var1, long long int L64_var2 )
    2352             : {
    2353  1521565607 :     int F_ret = 0;
    2354             : 
    2355  1521565607 :     if ( L64_var1 < L64_var2 )
    2356             :     {
    2357   251292994 :         F_ret = 1;
    2358             :     }
    2359             : #ifdef WMOPS
    2360             :     multiCounter[currCounter].LT_64++;
    2361             : #endif
    2362  1521565607 :     return F_ret;
    2363             : }
    2364             : 
    2365             : int GT_64( long long int L64_var1, long long int L64_var2 )
    2366             : {
    2367   531116969 :     int F_ret = 0;
    2368             : 
    2369   531116969 :     if ( L64_var1 > L64_var2 )
    2370             :     {
    2371   140842901 :         F_ret = 1;
    2372             :     }
    2373             : #ifdef WMOPS
    2374             :     multiCounter[currCounter].GT_64++;
    2375             : #endif
    2376   531116969 :     return F_ret;
    2377             : }
    2378             : 
    2379             : int LE_64( long long int L64_var1, long long int L64_var2 )
    2380             : {
    2381    12518150 :     int F_ret = 0;
    2382             : 
    2383    12518150 :     if ( L64_var1 <= L64_var2 )
    2384             :     {
    2385     1625600 :         F_ret = 1;
    2386             :     }
    2387             : #ifdef WMOPS
    2388             :     multiCounter[currCounter].LE_64++;
    2389             : #endif
    2390    12518150 :     return F_ret;
    2391             : }
    2392             : int GE_64( long long int L64_var1, long long int L64_var2 )
    2393             : {
    2394   262735865 :     int F_ret = 0;
    2395             : 
    2396   262735865 :     if ( L64_var1 >= L64_var2 )
    2397             :     {
    2398    62440630 :         F_ret = 1;
    2399             :     }
    2400             : #ifdef WMOPS
    2401             :     multiCounter[currCounter].GE_64++;
    2402             : #endif
    2403   262735865 :     return F_ret;
    2404             : }
    2405             : 
    2406             : int EQ_64( long long int L64_var1, long long int L64_var2 )
    2407             : {
    2408     3349853 :     int F_ret = 0;
    2409             : 
    2410     3349853 :     if ( L64_var1 == L64_var2 )
    2411             :     {
    2412       39018 :         F_ret = 1;
    2413             :     }
    2414             : #ifdef WMOPS
    2415             :     multiCounter[currCounter].EQ_64++;
    2416             : #endif
    2417     3349853 :     return F_ret;
    2418             : }
    2419             : int NE_64( long long int L64_var1, long long int L64_var2 ) 
    2420             : {
    2421    29157647 :     int F_ret = 0;
    2422             : 
    2423    29157647 :     if ( L64_var1 != L64_var2 )
    2424             :     {
    2425     5220323 :         F_ret = 1;
    2426             :     }
    2427             : #ifdef WMOPS
    2428             :     multiCounter[currCounter].NE_64++;
    2429             : #endif
    2430    29157647 :     return F_ret;
    2431             : }
    2432             : 
    2433             : #endif /* #ifdef CONTROL_CODE_OPS */
    2434             : 
    2435             : #ifdef WMOPS
    2436             : 
    2437             : void incrIf( const char *func_name )
    2438             : {
    2439             :     /* Technical note: If the "IF" operator comes just after an "ELSE", its counter must not be incremented */
    2440             :     /* The following auxiliary variables are used to check if the "IF" operator doesn't immediately follow an "ELSE" operator */
    2441             :     if ( ( strncmp( func_name, func_name_where_last_call_to_else_occurred, MAX_FUNCTION_NAME_LENGTH ) != 0 ) || ( TotalWeightedOperation( currCounter ) != funcid_total_wmops_at_last_call_to_else ) )
    2442             :     {
    2443             : 
    2444             :         multiCounter[currCounter].If++;
    2445             :     }
    2446             : 
    2447             :     func_name_where_last_call_to_else_occurred[0] = '\0';
    2448             : }
    2449             : 
    2450             : void incrElse( const char *func_name )
    2451             : {
    2452             :     multiCounter[currCounter].If++;
    2453             : 
    2454             :     /* Save the BASOP comeplxity in the last call of the ELSE() statement */
    2455             :     funcid_total_wmops_at_last_call_to_else = TotalWeightedOperation( currCounter );
    2456             : 
    2457             :     /* We keep track of the name of the last calling function when the ELSE macro was called */
    2458             :     strncpy( func_name_where_last_call_to_else_occurred, func_name, MAX_FUNCTION_NAME_LENGTH );
    2459             :     func_name_where_last_call_to_else_occurred[MAX_FUNCTION_NAME_LENGTH] = '\0';
    2460             : }
    2461             : 
    2462             : long TotalWeightedOperation( unsigned int CounterId )
    2463             : {
    2464             :     int i;
    2465             :     unsigned int *ptr, *ptr2;
    2466             :     long tot;
    2467             : 
    2468             :     tot = 0;
    2469             :     ptr = (unsigned int *) &multiCounter[CounterId];
    2470             :     ptr2 = (unsigned int *) &op_weight;
    2471             : 
    2472             :     for ( i = 0; i < (int) ( sizeof( multiCounter[CounterId] ) / sizeof( unsigned int ) ); i++ )
    2473             :     {
    2474             :         if ( *ptr == UINT_MAX )
    2475             :         {
    2476             :             printf( "\nError in BASOP complexity counters: multiCounter[%d][%d] = %d !!!\n", CounterId, i, *ptr );
    2477             :             exit( -1 );
    2478             :         }
    2479             : 
    2480             :         tot += ( ( *ptr++ ) * ( *ptr2++ ) );
    2481             :     }
    2482             : 
    2483             :     return ( tot );
    2484             : }
    2485             : 
    2486             : long DeltaWeightedOperation( unsigned int CounterId )
    2487             : {
    2488             :     long NewWOper, delta;
    2489             : 
    2490             :     NewWOper = TotalWeightedOperation( CounterId );
    2491             : 
    2492             :     delta = NewWOper - wmops[CounterId].LastWOper;
    2493             :     wmops[CounterId].LastWOper = NewWOper;
    2494             : 
    2495             :     return ( delta );
    2496             : }
    2497             : 
    2498             : /* Resets BASOP operation counter */
    2499             : void Reset_BASOP_WMOPS_counter( unsigned int counterId )
    2500             : {
    2501             :     int i;
    2502             :     unsigned int *ptr;
    2503             : 
    2504             :     /* reset the current BASOP operation counter */
    2505             :     ptr = (unsigned int *) &multiCounter[counterId];
    2506             :     for ( i = 0; i < (int) (sizeof(BASIC_OP) / sizeof(unsigned int)); i++ )
    2507             :     {
    2508             :         *ptr++ = 0;
    2509             :     }
    2510             : 
    2511             :     wmops[counterId].LastWOper = 0;
    2512             : 
    2513             :     return;
    2514             : }
    2515             : 
    2516             : #endif

Generated by: LCOV version 1.14