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
|