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

Generated by: LCOV version 1.14