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