Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / verif / env / fnx / clib / report / cc / report_pli.cc
CommitLineData
86530b38
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: report_pli.cc
4// Copyright (C) 1995-2007 Sun Microsystems, Inc. All Rights Reserved
5// 4150 Network Circle, Santa Clara, California 95054, U.S.A.
6//
7// * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8//
9// This program is free software; you can redistribute it and/or modify
10// it under the terms of the GNU General Public License as published by
11// the Free Software Foundation; version 2 of the License.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21//
22// For the avoidance of doubt, and except that if any non-GPL license
23// choice is available it will apply instead, Sun elects to use only
24// the General Public License version 2 (GPLv2) at this time for any
25// software where a choice of GPL license versions is made
26// available with the language indicating that GPLv2 or any later version
27// may be used, or where a choice of which version of the GPL is applied is
28// otherwise unspecified.
29//
30// Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
31// CA 95054 USA or visit www.sun.com if you need additional information or
32// have any questions.
33//
34// ========== Copyright Header End ============================================
35// Test if GNU gcc version is less than 3.x. If so, use pre-standard lib includes
36#if __GNUC__ < 3
37// VSP-modification end
38
39//#include <iostream.h>
40#include <stdio.h>
41#include <string.h>
42#include <time.h>
43#include <limits.h>
44
45// VSP-modification begin
46#else
47
48#include <iostream>
49#include <cstdarg>
50#include <string>
51#include <ctime>
52#include <limits>
53
54#endif // else __GNUC__ < 3
55// VSP-modification end
56
57#include <sys/types.h>
58#include <sys/times.h>
59#include <unistd.h>
60#include <cReport.h>
61#include <report_info.h>
62#include <Hash.h>
63#include <veriuser.h>
64
65// utility functions
66extern void parse_format_string(char*, char*, int);
67extern int regex_match(const char*, const char*);
68
69#ifdef __cplusplus
70extern "C" {
71#endif
72
73// Global variables
74HashTable *g_report_hash_table;
75int g_report_hash_table_initialized = 0;
76ReportClass g_internal_reports; // for report utility information
77int g_cycle_count = 0, g_death_cycle_count;
78int g_exit_on_error = 1;
79clock_t start_time;
80struct tms start_tmsbuf;
81
82////////////////////////////////////////////////////////////////////////////////
83// PLI accessor functions
84
85//
86// ReportClass_report
87//
88// PLI accessor for the function ReportClass::report()
89//
90//
91void ReportClass_report()
92{
93 const HashValueListNode *this_key, *this_value;
94 const char *mip_name = tf_mipname(); // Stash the module pathname in mip_name.
95 ReportType report_type = (ReportType)tf_getp(1);
96
97 // Create a key and retrieve the correct ReportClass* from the hash.
98 this_key = new HashValueListNode(mip_name, report_type); this_value = g_report_hash_table->lookup(*this_key);
99 if (this_value == NULL) {
100 tf_error("ReportClass (Internal): Couldn't find value for key with mipname %s!\n",
101 mip_name);
102 tf_dofinish();
103 }
104 delete this_key;
105
106 {
107 ReportClass this_report = *this_value->report_class;
108
109 if (this_report.this_will_print(report_type)) {
110 char format_str[REPORT_MAX_LINE_LENGTH];
111 char time_str[REPORT_MAX_LINE_LENGTH];
112 char msg_str[REPORT_MAX_LINE_LENGTH];
113
114 // Parse the format string and argument list to produce a
115
116 strncpy(format_str, tf_getcstringp(2), REPORT_MAX_LINE_LENGTH); // make a copy so we can modify it in parse_format_string.
117 format_str[REPORT_MAX_LINE_LENGTH-1] = '\0';
118 parse_format_string(msg_str, format_str, 3);
119
120 // Generate the time string.
121 // - tack on simulation time if so desired.
122 if (ReportClass::get_show_simulation_time())
123 sprintf(time_str, "%d,%d", g_cycle_count, tf_gettime());
124 else
125 sprintf(time_str, "%d", g_cycle_count);
126
127 // Generate the location string, shortening the pathname if so desired.
128 if (ReportClass::get_short_pathnames()) {
129 const char * loc_p = strrchr(mip_name, '.');
130 mip_name = (loc_p == NULL) ? mip_name : ++loc_p;
131 }
132
133 // Actually make the report. Note that msg_str is always a simple
134 // string at this point, with no format chars.
135 this_report.report(report_type, time_str, mip_name, "%s", msg_str);
136 } else {
137 // no need for strings that won't print.
138 this_report.report(report_type, "", "", "%s", "");
139 }
140
141 }
142} // ReportClass_report
143
144
145// report_verilog_check
146//
147// This function is called at the beginning of simulation for each call
148// made in the design. This allows us to populate an hash table with a
149// pointer to each {report_type, instance_id} pair.
150//
151void report_verilog_check(void)
152{
153 int nparam;
154 HashValueListNode *key;
155
156 // first time through
157 if (g_report_hash_table_initialized == 0) {
158 // Instantiate a ReportClass object so we can use it to print and such.
159 //g_internal_reports = new ReportClass();
160 g_report_hash_table = new HashTable();
161 g_report_hash_table_initialized++;
162 }
163
164 // check that we have at least 2 parameters
165 nparam = tf_nump();
166 if( nparam < 2 ) {
167 tf_error("$report: (%s) line: %d; Too few arguments to ",
168 __FILE__,__LINE__);
169 tf_dofinish();
170 }
171
172 // Check that the report's arguments are valid.
173 {
174 const char *index;
175 int nformats = 0;
176
177 // Check that print format characters belong to the set [hHdDoObBsS]
178 index = tf_getcstringp(2);
179 while( *index ) {
180 if( *index == '%' ) {
181 index++;
182 switch( *index ) {
183 case 'h': case 'H':
184 case 'd': case 'D':
185 case 'o': case 'O':
186 case 'b': case 'B':
187 case 's': case 'S':
188 nformats++;
189 case '%':
190 break;
191 default : {
192 tf_error("$report: (%s) line: %d; Illegal format to : \"%%%c\"",
193 __FILE__,__LINE__, (char)*index);
194 tf_dofinish();
195 }
196 } // switch()
197 }
198 index++;
199 }
200
201
202 // Check that there are at least as many parameters as formats
203 if (nformats > (nparam - 2)) {
204 tf_error("$report: (%s) line: %d: Missing arguments to $report call (%d expected, %d found)",
205 __FILE__,__LINE__, nformats, nparam-2);
206 tf_dofinish();
207 }
208 } // done checking args
209
210 {
211 const char *mip_name = tf_mipname();
212 ReportType report_type = (ReportType)tf_getp(1);
213
214 if (!is_report_type_valid(report_type)) {
215 tf_error("$report: (%s) line: %d; Invalid report type in %s: %d",
216 __FILE__, __LINE__, mip_name, report_type);
217 }
218
219 // Build a new hash key for this report and insert it into the table.
220 key = new HashValueListNode(mip_name, report_type);
221 if (key == 0) {
222 tf_error("report_verilog_check:: unable to allocate space for new HashValueListNode");
223 }
224
225 // Insert our element into the list
226 if (g_report_hash_table->lookup(*key) == NULL) {
227 key->report_class = new ReportClass();
228 g_report_hash_table->insert(key);
229 } else {
230 delete key;
231 }
232 }
233
234} // report_verilog_check
235
236
237//////////////////////////////////////////////////////////////////
238// Wrappers for setting default states.
239//
240// Set the *default* print level per type. The change applies to all report
241// objects for which set_print_level() has not been called previously.
242void ReportClass_set_default_print_level() {
243 ReportType type = (ReportType) tf_getp(1);
244 PrintLevel pl = (PrintLevel) tf_getp(2);
245
246 g_internal_reports.set_default_print_level(type, pl);
247}
248
249// Set the *default* error level per type. The change applies to all report
250// objects for which set_error_level() has not been called previously.
251void ReportClass_set_default_error_level() {
252 ReportType type = (ReportType) tf_getp(1);
253 ErrorLevel el = (ErrorLevel) tf_getp(2);
254
255 g_internal_reports.set_default_error_level(type, el);
256}
257
258// Set the *default* table_mode per type. The change applies to all report
259// objects for which set_table_mode() has not been called previously.
260void ReportClass_set_default_table_mode() {
261 ReportType type = (ReportType) tf_getp(1);
262 int mode = (int) tf_getp(2);
263
264 g_internal_reports.set_default_table_mode(type, mode);
265}
266
267
268////////////////////////////////////////////////////////////////////////////////
269// PLI accessors for ReportClass instance variables
270
271/*
272 * ReportClass_set_print_level( regexp, report_type, print_level )
273 *
274 * This function performs the same tasks as "pos_level_control" did for pos_report.
275 * Its arguments are:
276 *
277 * (1) regular expression -- matches the hierarchical paths for which the
278 * print level should be changed
279 *
280 * (2) report type -- the message types which should be changed. Using
281 * ALL_REPORTS as the report type will change the print level for all
282 * messages that match the regexp.
283 *
284 * (3) print level -- the level to which the matching classes should be set
285 *
286 * example:
287 * to suppress all timeout reporting and failures in the "mdu"
288 * instance and all instances beneath it:
289 *
290 * (".*\.mdu\..*", RTYP_TIMEOUT, RPRT_NOP);
291 *
292 * note that because periods are special regular expression characters
293 * they must be escaped.
294 *
295 * If no matches are found for the regex_pattern a warning will be printed. */
296void ReportClass_set_print_level() {
297 char *match_pattern = tf_getcstringp(1);
298 ReportType type = (ReportType) tf_getp(2);
299 PrintLevel pl = (PrintLevel) tf_getp(3);
300 int regex_status;
301 int found_match = 0;
302 const HashValueListNode *value = NULL;
303 char prefixed_pattern[REPORT_MAX_FIELD_WIDTH];
304
305 // Check that the arguments are valid.
306 if (!is_report_type_valid(type))
307 tf_error("ReportClass::set_print_level: Invalid report type (%d) to ", type);
308 if (!is_print_level_valid(pl))
309 tf_error("ReportClass::set_print_level: Invalid print level (%d) to ", pl);
310
311
312 strcpy(prefixed_pattern, ReportClass::get_path_prefix());
313 strncat(prefixed_pattern, match_pattern, REPORT_MAX_FIELD_WIDTH-strlen(prefixed_pattern));
314 regex_status = regex_match(prefixed_pattern, "");
315 if (regex_status == 2) {
316 tf_error("ReportClass::set_print_level: Bad regular expression (%s)", prefixed_pattern);
317 tf_dofinish();
318 }
319
320 // Walk through the hash, finding entries which match the regexp.
321 g_report_hash_table->start_walk();
322 while (value = g_report_hash_table->next_element()) {
323 // Attempt to match the stored pathname to the pre-compiled regular expression.
324 regex_status = regex_match(NULL, value->mip_name);
325
326 // Actually set the print level if we have a match. We have to
327 // construct our own report to tell the user about this, since the
328 // ReportClass itself doesn't know time or location.
329 if (regex_status == 0) {
330 char cycle_str[REPORT_MAX_FIELD_WIDTH];
331 value->report_class->set_print_level(type, pl, TRUE); // silently -- class doesn't know the path
332 sprintf(cycle_str, "%d", g_cycle_count);
333 g_internal_reports.report(RTYP_REPORT_MSG,
334 cycle_str, value->mip_name,
335 "Setting print level for report type %s to %s",
336 report_type_to_str(value->report_type),
337 print_level_to_str(pl));
338 found_match = 1;
339 }
340 }
341
342 if (!found_match)
343 tf_warning("ReportClass (Internal): Could not find match for regular expression \"%s\"\n", prefixed_pattern);
344
345}
346
347
348/*
349 * report_set_error_level
350 *
351 * This function sets the error level for a given instance of ReportClass.
352 * It follows the same semantics as "set_print_level" above.
353 */
354void ReportClass_set_error_level()
355{
356 char *match_pattern = tf_getcstringp(1);
357 ReportType type = (ReportType) tf_getp(2);
358 ErrorLevel el = (ErrorLevel) tf_getp(3);
359 int regex_status;
360 int found_match = 0;
361 const HashValueListNode *value = NULL;
362 char prefixed_pattern[REPORT_MAX_FIELD_WIDTH];
363
364 // Check that the arguments are valid.
365 if (!is_report_type_valid(type))
366 tf_error("ReportClass::set_error_level: Invalid report type (%d) to ", type);
367 if (!is_error_level_valid(el))
368 tf_error("ReportClass::set_error_level: Invalid error level (%d) to ", el);
369
370
371 strcpy(prefixed_pattern, ReportClass::get_path_prefix());
372 strncat(prefixed_pattern, match_pattern, REPORT_MAX_FIELD_WIDTH-strlen(prefixed_pattern));
373 regex_status = regex_match(match_pattern, "");
374 if (regex_status == 2) {
375 tf_error("ReportClass::set_error_level): Bad regular expression (%s)", match_pattern);
376 tf_dofinish();
377 }
378
379 // Walk through the hash, finding entries which match the regexp.
380 g_report_hash_table->start_walk();
381 while (value = g_report_hash_table->next_element()) {
382 // Attempt to match the stored pathname to the pre-compiled regular expression.
383 regex_status = regex_match(NULL, value->mip_name);
384
385 // Actually set table mode for the matching instances. We do this silently.
386 if (regex_status == 0) {
387 char cycle_str[REPORT_MAX_FIELD_WIDTH];
388 value->report_class->set_error_level(type, el, TRUE);
389 sprintf(cycle_str, "%d", g_cycle_count);
390 g_internal_reports.report(RTYP_REPORT_MSG,
391 cycle_str, value->mip_name,
392 "Setting error level for report type %s to %s",
393 report_type_to_str(value->report_type),
394 error_level_to_str(el));
395 found_match = 1;
396 }
397 }
398
399 if (!found_match)
400 tf_warning("ReportClass (Internal): Could not find match for regular expression \"%s\"\n", match_pattern);
401}
402
403
404/*
405 * ReportClass_set_table_mode
406 *
407 * This function sets the "table mode" parameter for a given instance of ReportClass.
408 * It follows the same semantics as the "set_print_level" function above.
409 *
410 * Placing a particular message type in table mode will:
411 * - remove the prefixes from its output
412 * - remove automatic carriage returns from its output
413 * This might be useful for (duh) printing tables of information, statistics, etc.
414 *
415 */
416void ReportClass_set_table_mode()
417{
418 char *match_pattern = tf_getcstringp(1);
419 ReportType type = (ReportType) tf_getp(2);
420 int table_mode = tf_getp(3);
421 int regex_status;
422 int found_match = 0;
423 const HashValueListNode *value = NULL;
424 char prefixed_pattern[REPORT_MAX_FIELD_WIDTH];
425
426 // Check that the arguments are valid.
427 if (!is_report_type_valid(type))
428 tf_error("ReportClass::set_table_mode: Invalid report type (%d) to ", type);
429
430
431 strcpy(prefixed_pattern, ReportClass::get_path_prefix());
432 strncat(prefixed_pattern, match_pattern, REPORT_MAX_FIELD_WIDTH-strlen(prefixed_pattern));
433 regex_status = regex_match(match_pattern, "");
434 if (regex_status == 2) {
435 tf_error("ReportClass::set_table_mode: Bad regular expression (%s)", match_pattern);
436 tf_dofinish();
437 }
438
439 // Walk through the hash, finding entries which match the regexp.
440 g_report_hash_table->start_walk();
441 while (value = g_report_hash_table->next_element()) {
442 // Attempt to match the stored pathname to the pre-compiled regular expression.
443 regex_status = regex_match(NULL, value->mip_name);
444
445 // Actually set table mode for the matching instances. We do this silently.
446 if (regex_status == 0) {
447 char cycle_str[REPORT_MAX_FIELD_WIDTH];
448 value->report_class->set_table_mode(type, table_mode, 1); // silently
449 sprintf(cycle_str, "%d", g_cycle_count);
450 g_internal_reports.report(RTYP_REPORT_MSG,
451 cycle_str, value->mip_name,
452 "Setting table mode for report type %s to %s",
453 report_type_to_str(value->report_type),
454 table_mode ? "ON" : "OFF");
455 found_match = 1;
456 }
457 }
458
459 if (!found_match)
460 tf_warning("ReportClass (Internal): Could not find match for regular expression \"%s\"\n", match_pattern);
461}
462
463////////////////////////////////////////////////////////////////////////////////
464// PLI accessors for ReportClass static variables
465
466/*
467 * ReportClass_set_global_print_threshold(int print_level, (int locked_by = REPORT_LOCKED_BY_NO_ONE))
468 *
469 */
470void ReportClass_set_global_print_threshold()
471{
472 PrintLevel pl = (PrintLevel) tf_getp(1);
473 if (!is_print_level_valid(pl))
474 tf_error("ReportClass (Internal): Invalid print level %d to ", pl);
475 if (tf_nump() > 1)
476 {
477 // Lock parameter specified -- pass it along to C++.
478 int lock = tf_getp(2);
479 ReportClass::set_global_print_threshold(pl, lock);
480 }
481 else
482 {
483 // No lock specified.
484 ReportClass::set_global_print_threshold(pl);
485 }
486}
487
488/*
489 * ReportClass_get_global_print_threshold
490 *
491 */
492void ReportClass_get_global_print_threshold()
493{
494 tf_putp(0, (int)ReportClass::get_global_print_threshold());
495 return;
496}
497
498/*
499 * ReportClass_set_max_error_count()
500 *
501 */
502void ReportClass_set_max_error_count()
503{
504 int ec = tf_getp(1);
505 if (ec > 0)
506 ReportClass::set_max_error_count(ec);
507 else
508 tf_error("ReportClass (Internal): Invalid error count (%d) passed to ", ec);
509}
510
511/*
512 * ReportClass_get_max_error_count
513 *
514 */
515void ReportClass_get_max_error_count()
516{
517 tf_putp(0, ReportClass::get_max_error_count());
518 return;
519}
520
521/*
522 * ReportClass_inc_global_error_count()
523 *
524 */
525void ReportClass_inc_global_error_count()
526{
527 ReportClass::inc_global_error_count();
528 return;
529}
530
531/*
532 * ReportClass_get_global_error_count
533 */
534void ReportClass_get_global_error_count()
535{
536 tf_putp(0, ReportClass::get_global_error_count());
537 return;
538}
539
540/*
541 * ReportClass_inc_global_warning_count()
542 */
543void ReportClass_inc_global_warning_count()
544{
545 ReportClass::inc_global_warning_count();
546 return;
547}
548
549/*
550 * ReportClass_get_global_warning_count()
551 *
552 */
553void ReportClass_get_global_warning_count()
554{
555 tf_putp(0, ReportClass::get_global_warning_count());
556 return;
557}
558
559/*
560 * ReportClass_set_short_pathnames
561 */
562void ReportClass_set_short_pathnames()
563{
564 ReportClass::set_short_pathnames(tf_getp(1));
565 return;
566}
567
568/*
569 * ReportClass_get_short_pathnames
570 */
571void ReportClass_get_short_pathnames()
572{
573 tf_putp(0, ReportClass::get_short_pathnames());
574 return;
575}
576
577/*
578 * ReportClass_set_path_prefix
579 */
580void ReportClass_set_path_prefix()
581{
582 ReportClass::set_path_prefix(tf_getcstringp(1));
583 return;
584}
585
586/*
587 * ReportClass_get_path_prefix
588 */
589void ReportClass_get_path_prefix()
590{
591 // review: How to return a string value via the PLI?
592 return;
593}
594
595/*
596 * ReportClass_disable_fatal_errors
597 */
598void ReportClass_disable_fatal_errors()
599{
600 ReportClass::disable_fatal_errors(tf_getp(1));
601 return;
602}
603
604/*
605 * ReportClass_get_num_remaining_nonfatal_cycles
606 */
607void ReportClass_get_num_remaining_nonfatal_cycles()
608{
609 tf_putp(0, ReportClass::get_num_remaining_nonfatal_cycles());
610 return;
611}
612
613/*
614 * ReportClass_set_show_simulation_time
615 */
616void ReportClass_set_show_simulation_time()
617{
618 ReportClass::set_show_simulation_time(tf_getp(1));
619 return;
620}
621
622/*
623 * ReportClass_get_show_simulation_time
624 */
625void ReportClass_get_show_simulation_time()
626{
627 tf_putp(0, ReportClass::get_show_simulation_time());
628 return;
629}
630
631////////////////////////////////////////////////////////////////////////////////
632// Other PLI calls
633
634/*
635 * report_inc_cycle_count
636 *
637 */
638void report_inc_cycle_count()
639{
640 // Increment the cycle count, which is kept in the PLI as a global.
641 g_cycle_count++;
642
643 // If the ReportClass has errors disabled, decrement the its number
644 // of remaining nonfatal cycles.
645 if (ReportClass::get_num_remaining_nonfatal_cycles() > 0) {
646 ReportClass::dec_num_remaining_nonfatal_cycles();
647 }
648
649 if (g_death_cycle_count && (g_cycle_count >= g_death_cycle_count)) {
650 io_printf("Report:(%0d) [PLI] calling for error which occured at cycle %0d\n",
651 g_cycle_count, g_cycle_count - REPORT_DEATH_CYCLE_DELAY);
652 tf_dofinish();
653 }
654}
655
656/*
657 * report_set_exit_on_error
658 *
659 */
660void report_set_exit_on_error()
661{
662 int x = tf_getp(1);
663 io_printf("Report:() Setting exit on error to %0d\n", x);
664 g_exit_on_error = x;
665 return;
666}
667
668/*
669 * report_get_exit_on_error
670 *
671 */
672void report_get_exit_on_error()
673{
674 tf_putp(0, g_exit_on_error);
675 return;
676}
677
678////////////////////////////////////////////////////////////////////////////////
679// System functions
680
681/*
682 * check_number_of_args()
683 *
684 * Called at compile time to ensure that each PLI call is made with
685 * the expected number of arguments. The number of arguments is
686 * specified in the PLI .tab file as a data parameter to this function.
687 *
688 */
689void check_number_of_args( long expected_args ) {
690 if( tf_nump() != expected_args ) {
691 tf_error("(%s) line: %d; wrong number of arguments to pli call. expected %d args",
692 __FILE__,__LINE__,expected_args);
693 exit(1);
694 }
695 return;
696}
697
698/*
699 * do_cleanup()
700 *
701 * This function is called at the end of simulation.
702 */
703static void do_cleanup(int code) {
704
705}
706
707/*
708 * set_start_timestamp
709 *
710 * Called at "elaboration time" as a PLI check function for print_cycles_per_second.
711 * Places the wall-clock time into a global variable for calculation the CPS of this sim.
712 *
713 */
714void set_start_timestamp()
715{
716 start_time = times(&start_tmsbuf);
717}
718
719/*
720 * print_cycles_per_second
721 *
722 * Called by report_test_complete() in Vera land to output
723 * the performance in cycles/sec for this simulation.
724 *
725 */
726void report_print_cycles_per_second()
727{
728 clock_t end_time;
729 struct tms end_tmsbuf;
730 double cps_cpu;
731 double elapsed_time_cpu;
732 char *top;
733
734 end_time = times(&end_tmsbuf);
735
736 // Total CPU Time is sum of user and system CPU time for calling and child processes
737 elapsed_time_cpu = (double) ((end_tmsbuf.tms_utime - start_tmsbuf.tms_utime) + // Calling Process User Time
738 (end_tmsbuf.tms_stime - start_tmsbuf.tms_stime) + // Calling Process System Time
739 (end_tmsbuf.tms_cutime - start_tmsbuf.tms_cutime) + // Child Processes User Time
740 (end_tmsbuf.tms_cstime - start_tmsbuf.tms_cstime)) // Child Processes System Time
741 / CLK_TCK ; // Divide by clock ticks per second
742
743 // Avoid division by zero, make sure elapsed time is at least 1/CLK_TCK seconds
744 if (elapsed_time_cpu <= 0)
745 elapsed_time_cpu = 1/CLK_TCK;
746
747 cps_cpu = g_cycle_count/elapsed_time_cpu;
748
749 top = (char *)sbrk(0);
750
751 io_printf("Report:: Total CPU Time (seconds): %0.2f\n", elapsed_time_cpu);
752 io_printf("Report:: Effective cycles per second: %0.2f\n", cps_cpu);
753 io_printf("Report:: Apparent virtual memory size: %d bytes\n", top);
754 io_printf("================================================================================\n\n");
755}
756
757
758#ifdef __cplusplus
759}
760#endif