blob: 6033a2b46af538f4640fb0b6a00e6192fc5edc12 [file] [log] [blame]
#!/usr/bin/perl
###################################################################################
# This script is used to extract and verify statistics of one or more VTR tasks.
#
# Usage:
# parse_vtr_task.pl <task_name1> <task_name2> ... [OPTIONS]
#
# Options:
# -l <task_list_file>: Used to provide a test file containing a list of tasks
# -create_golden: Will create/overwrite the golden results with those of the
# most recent execution
# -check_golden: Will verify the results of the most recent execution against
# the golden results for each task and report either a
# [Pass] or [Fail]
# -parse_qor: Used for the purposes of parsing quality of results of the
# most recent execution.
# -calc_geomean: Used for the purposes of computing quality of results geomeans
# of the most recent execution.
#
# Authors: Jason Luu and Jeff Goeders
###################################################################################
use strict;
use Cwd;
use File::Spec;
use File::Copy;
use File::Basename;
use List::Util;
use Math::BigInt;
use POSIX qw/strftime/;
# Function Prototypes
sub trim;
sub parse_single_task;
sub pretty_print_table;
sub summarize_qor;
sub calc_geomean;
sub check_golden;
sub expand_user_path;
sub get_important_file;
sub parse_single_flow_run;
sub aggregate_single_flow_runs;
# Get Absolute Path of 'vtr_flow
Cwd::abs_path($0) =~ m/(.*vtr_flow)/;
my $vtr_flow_path = $1;
my $run_prefix = "run";
my $FAILED_PARSE_EXIT_CODE = -1;
# Parse Input Arguments
my @tasks;
my @task_files;
my $token;
my $create_golden = 0;
my $check_golden = 0;
my $parse_qor = 1; # QoR file is parsed by default; turned off if
# user does not specify QoR parse file in config.txt
my $calc_geomean = 0; # QoR geomeans are not computed by default;
my $override_exp_id = 0;
my $revision;
my $verbose = 0;
my $pretty_print_results = 1;
while ( $token = shift(@ARGV) ) {
# Check for a task list file
if ( $token =~ /^-l(.+)$/ ) {
push( @task_files, expand_user_path($1) );
}
elsif ( $token eq "-l" ) {
push( @task_files, expand_user_path( shift(@ARGV) ) );
}
elsif ( $token eq "-create_golden" ) {
$create_golden = 1;
}
elsif ( $token eq "-check_golden" ) {
$check_golden = 1;
}
elsif ( $token eq "-parse_qor" ) {
$parse_qor = 1;
}
elsif ( $token eq "-calc_geomean" ) {
$calc_geomean = 1;
}
elsif ( $token eq "-run") {
$override_exp_id = shift(@ARGV);
}
elsif ( $token eq "-revision" ) {
$revision = shift(@ARGV);
}
elsif ( $token eq "-v" ) {
$verbose = 1;
}
elsif ( $token =~ /^-/ ) {
die "Invalid option: $token\n";
}
# must be a task name
else {
if ( $token =~ /(.*)\/$/ ) {
$token = $1;
}
push( @tasks, $token );
}
}
# Read Task Files
foreach (@task_files) {
open( FH, $_ ) or die "$! ($_)\n";
while (<FH>) {
push( @tasks, $_ );
}
close(FH);
}
my $num_golden_failures = 0;
foreach my $task (@tasks) {
chomp($task);
my $failures = parse_single_task($task);
$num_golden_failures += $failures;
}
if ($calc_geomean) {
summarize_qor;
calc_geomean;
}
exit $num_golden_failures;
sub parse_single_task {
my $task_name = shift;
(my $task_path = $task_name) =~ s/\s+$//;
# first see if task_name is the task path
if (! -e "$task_path/config/config.txt") {
($task_path = "$vtr_flow_path/tasks/$task_name") =~ s/\s+$//;
}
open( CONFIG, "<$task_path/config/config.txt" )
or die "Failed to open $task_path/config/config.txt: $!\n";
my @config_data = <CONFIG>;
close(CONFIG);
my @archs_list;
my @circuits_list;
my @script_params_list;
my $parse_file;
my $qor_parse_file;
my $second_parse_file;
my $counter = 0;
foreach my $line (@config_data) {
# Ignore comments
if ( $line =~ /^\s*#.*$/ or $line =~ /^\s*$/ ) { next; }
#Trim off a line-ending comment
$line =~ s/#.*$//;
my @data = split( /=/, $line );
my $key = trim( $data[0] );
my $value = trim( $data[1] );
if ( $key eq "circuit_list_add" ) {
push( @circuits_list, $value );
} elsif ( $key eq "arch_list_add" ) {
push( @archs_list, $value );
} elsif ( $key eq "script_params_list_add" ) {
push( @script_params_list, $value );
} elsif ( $key eq "parse_file" ) {
if ($counter eq 1){
#second time parse file
$second_parse_file = expand_user_path($value);
$counter = 0;
#don't need to check golden, only compare between two files
$check_golden = 0;
}
else{
$parse_file = expand_user_path($value);
$counter = $counter + 1;
}
} elsif ( $key eq "qor_parse_file" ) {
$qor_parse_file = expand_user_path($value);
}
}
if (!@script_params_list) {
#Add a default empty param if none otherwise specified
#(i.e. only base params)
push(@script_params_list, "");
}
# PARSE CONFIG FILE
if ( $parse_file eq "" ) {
die "Task $task_name has no parse file specified.\n";
}
$parse_file = get_important_file($task_path, $vtr_flow_path, $parse_file);
if ($second_parse_file){
$second_parse_file = get_important_file($task_path, $vtr_flow_path, $second_parse_file);
}
# Get Max Run #
opendir(DIR, $task_path);
my @folders = readdir(DIR);
closedir(DIR);
# QOR PARSE CONFIG FILE
if ( $qor_parse_file eq "" ) {
print "Task $task_name has no QoR parse file specified. Skipping QoR.\n";
$parse_qor = 0;
$calc_geomean = 0;
}
else {
$qor_parse_file = get_important_file($task_path, $vtr_flow_path, $qor_parse_file);
}
my $exp_id = 0;
if($override_exp_id != 0) {
#explicitely specified via -run parameter
$exp_id = $override_exp_id;
} else {
# haven't explicitely specified via -run parameter
$exp_id = last_exp_id(${task_path});
}
my $run_path = "$task_path/${run_prefix}${exp_id}";
my @first_run_result_files;
my @second_run_result_files;
my @qor_run_result_files;
foreach my $arch (@archs_list) {
foreach my $circuit (@circuits_list) {
foreach my $script_params (@script_params_list) {
my $script_params_dirname = "common";
if ($script_params ne "") {
$script_params_dirname .= "_" . $script_params;
$script_params_dirname =~ s/ /_/g;
}
#First run parse
my $work_dir = "$run_path/$arch/$circuit/$script_params_dirname";
my $output_filepath = "$work_dir/parse_results.txt";
my $config_prefix = "arch\tcircuit\tscript_params";
my $config_values = "arch=$arch" . " circuit=$circuit" . " script_params=$script_params_dirname";
parse_single_flow_run($work_dir, $config_values, $parse_file, $output_filepath);
push(@first_run_result_files, $output_filepath);
if($second_parse_file){
my $output_filepath = "$work_dir/parse_results_2.txt";
parse_single_flow_run($work_dir, $config_values, $second_parse_file, $output_filepath);
push(@second_run_result_files, $output_filepath);
}
if ($parse_qor) {
my $output_filepath = "$work_dir/qor_results.txt";
parse_single_flow_run($work_dir, $config_values, $qor_parse_file, $output_filepath);
push(@qor_run_result_files, $output_filepath);
}
}
}
}
if (@first_run_result_files) {
aggregate_single_flow_runs(\@first_run_result_files, "$run_path/parse_results.txt");
}
if (@second_run_result_files) {
aggregate_single_flow_runs(\@second_run_result_files, "$run_path/parse_results_2.txt");
}
if (@qor_run_result_files) {
aggregate_single_flow_runs(\@qor_run_result_files, "$run_path/qor_results.txt");
}
if ($create_golden) {
copy( "$run_path/parse_results.txt", "$run_path/../config/golden_results.txt" );
}
if ($second_parse_file){
#don't check with golden results, just check the two files
return check_two_files ( $task_name, $task_path, $run_path, "$run_path/parse_results.txt", "$run_path/parse_results_2.txt", 0);
}
if ($check_golden) {
#Returns 1 if failed
if ($second_parse_file eq ""){
return check_two_files( $task_name, $task_path, $run_path, "$run_path/parse_results.txt", "$task_path/config/golden_results.txt", $check_golden);
}
}
return 0; #Pass
}
sub parse_single_flow_run {
my ($run_dir, $config_values, $parse_file, $output_file_path) = @_;
my $cmd = join(" ", "$vtr_flow_path/scripts/parse_vtr_flow.pl", $run_dir, $parse_file, $config_values, "> $output_file_path");
my $ret = system($cmd);
if ($ret != 0) {
print "System command '$cmd' failed\n";
exit $FAILED_PARSE_EXIT_CODE;
}
pretty_print_table($output_file_path);
}
sub aggregate_single_flow_runs {
my ($parse_result_files, $output_file_path) = @_;
my $first = 0;
open(OUTPUT_FILE, ">$output_file_path" );
my $size = @$parse_result_files;
for (my $i=0; $i < $size; $i++) {
my $result_file = @$parse_result_files[$i];
open(RESULT_FILE, $result_file);
my @lines = <RESULT_FILE>;
close(RESULT_FILE);
if ($i == 0) {
#First file add header
print OUTPUT_FILE $lines[0];
}
#Data
print OUTPUT_FILE $lines[1];
}
close(OUTPUT_FILE);
pretty_print_table($output_file_path);
}
sub summarize_qor {
##############################################################
# Set up output file
##############################################################
my $first = 1;
my $task = @tasks[0];
(my $task_path = $task) =~ s/\s+$//;
# first see if task_name is the task path
if (! -e "$task_path/config/config.txt") {
($task_path = "$vtr_flow_path/tasks/$task") =~ s/\s+$//;
}
my $output_path = $task_path;
my $exp_id = last_exp_id($task_path);
if ( ( ( $#tasks + 1 ) > 1 ) | ( -e "$task_path/../task_list.txt" ) ) {
$output_path = "$task_path/../";
}
if ( !-e "$output_path/task_summary" ) {
mkdir "$output_path/task_summary";
}
if ( -e "$output_path/task_summary/${run_prefix}${exp_id}_summary.txt" ) {
}
open( OUTPUT_FILE, ">$output_path/task_summary/${run_prefix}${exp_id}_summary.txt" );
##############################################################
# Append contents of QoR files to output file
##############################################################
foreach my $task (@tasks) {
chomp($task);
($task_path = $task) =~ s/\s+$//;
# first see if task_name is the task path
if (! -e "$task_path/config/config.txt") {
($task_path = "$vtr_flow_path/tasks/$task") =~ s/\s+$//;
}
$exp_id = last_exp_id($task_path);
(my $run_path = "$task_path/${run_prefix}${exp_id}") =~ s/\s+$//;
open( RESULTS_FILE, "$run_path/qor_results.txt" );
my $output = <RESULTS_FILE>;
if ($first) {
print OUTPUT_FILE "task_name\t$output";
$first = 0;
}
while ($output = <RESULTS_FILE>) {
print OUTPUT_FILE $task . "\t" . $output;
}
close(RESULTS_FILE);
}
close(OUTPUT_FILE);
}
sub calc_geomean {
##############################################################
# Set up output file
##############################################################
my $first = 0;
my $task = @tasks[0];
(my $task_path = $task) =~ s/\s+$//;
# first see if task_name is the task path
if (! -e "$task_path/config/config.txt") {
($task_path = "$vtr_flow_path/tasks/$task") =~ s/\s+$//;
}
my $output_path = $task_path;
my $exp_id = last_exp_id($task_path);
if ( ( ( $#tasks + 1 ) > 1 ) | ( -e "$task_path/../task_list.txt" ) ) {
($output_path = "$task_path/../") =~ s/\s+$//;
}
if ( !-e "$output_path/qor_geomean.txt" ) {
open( OUTPUT_FILE, ">$output_path/qor_geomean.txt" );
$first = 1;
}
else {
open( OUTPUT_FILE, ">>$output_path/qor_geomean.txt" );
}
##############################################################
# Read summary file
##############################################################
my $summary_file = "$output_path/task_summary/${run_prefix}${exp_id}_summary.txt";
if ( !-r $summary_file ) {
print "[ERROR] Failed to open $summary_file: $!\n";
return;
}
open( SUMMARY_FILE, "<$summary_file" );
my @summary_data = <SUMMARY_FILE>;
close(SUMMARY_FILE);
my $summary_params = shift @summary_data;
my @summary_params = split( /\t/, trim($summary_params) );
if ($first) {
# Hack - remove unwanted labels
my $num = 4;
while ($num) {
shift @summary_params;
--$num;
}
print OUTPUT_FILE "run";
my @temp = @summary_params;
while ( $#temp >= 0 ) {
my $label = shift @temp;
print OUTPUT_FILE "\t" . "$label";
}
print OUTPUT_FILE "\t" . "date" . "\t" . "revision";
$first = 0;
}
else {
}
print OUTPUT_FILE "\n${exp_id}";
##############################################################
# Compute & write geomean to output file
##############################################################
my $index = 4;
my @summary_params = split( /\t/, trim($summary_params) );
while ( $#summary_params >= $index ) {
my $geomean = 1; my $num = 0;
foreach my $line (@summary_data) {
my @first_file_line = split( /\t/, $line );
if ( trim( @first_file_line[$index] ) > 0 ) {
$geomean *= trim( @first_file_line[$index] );
$num++;
}
}
if ($num) {
$geomean **= 1/$num;
print OUTPUT_FILE "\t" . "${geomean}";
}
else {
print OUTPUT_FILE "\t" . "-1";
}
$index++;
}
my $date = strftime( '%D', localtime );
print OUTPUT_FILE "\t" . "$date" . "\t" . "$revision";
close(OUTPUT_FILE);
}
sub max {
my $x = shift;
my $y = shift;
return ($x < $y) ? $y : $x;
}
sub pretty_print_table {
my $file_path = shift;
#Read the input file
my @file_data;
open(INFILE,"<$file_path");
while(<INFILE>) {
chomp;
push(@file_data, [split /\t/])
}
#Determine the maximum column width for pretty formatting
my %col_widths;
for my $row (0 .. $#file_data) {
for my $col (0 .. $#{$file_data[$row]}) {
my $col_width = length $file_data[$row][$col];
#Do we have a valid column width?
if (not exists $col_widths{$col}) {
#Initial width
$col_widths{$col} = $col_width;
} else {
#Max width
$col_widths{$col} = max($col_widths{$col}, $col_width);
}
}
}
#Write out in pretty format
open(OUTFILE,">$file_path");
for my $row (0 .. $#file_data) {
for my $col (0 .. $#{$file_data[$row]}) {
printf OUTFILE "%-*s", $col_widths{$col}, $file_data[$row][$col];
if($col != $#{$file_data[$row]}) {
printf OUTFILE "\t";
}
}
printf OUTFILE "\n";
}
close(OUTFILE);
}
sub last_exp_id {
my $path = shift;
my $num = 0;
my $run_id = "";
my $run_id_no_pad = "";
do {
++$num;
$run_id = sprintf("%03d", $num);
$run_id_no_pad = sprintf("%d", $num);
} while ( -e "$path/${run_prefix}${run_id}" or -e "$path/${run_prefix}${run_id_no_pad}");
--$num;
$run_id = sprintf("%03d", $num);
$run_id_no_pad = sprintf("%d", $num);
if( -e "$path/${run_prefix}${run_id}" ) {
return $run_id;
} elsif (-e "$path/${run_prefix}${run_id_no_pad}") {
return $run_id_no_pad;
}
die("Unknown experiment id");
}
sub check_two_files {
my $task_name = shift;
my $task_path = shift;
my $run_path = shift;
my $first_test_file_dir = shift;
my $second_test_file_dir = shift;
my $is_golden = shift;
#Did this check pass?
my $failed = 0;
print "$task_name...";
print "\n" if $verbose;
# Code to check the results of the two files
(my $test_file_1 = "$first_test_file_dir") =~ s/\s+$//;
(my $test_file_2 = "$second_test_file_dir") =~ s/s+$//;
my $pass_req_file;
open( CONFIG_FILE, "$task_path/config/config.txt" );
my $lines = do { local $/; <CONFIG_FILE>; };
close(CONFIG_FILE);
# Search config file
if ( $lines =~ /^\s*pass_requirements_file\s*=\s*(\S+)\s*$/m ) {
my $pass_req_filename = $1;
if ($pass_req_filename !~ /^\s*%/) { #Not blank
# Search for pass requirement file
$pass_req_filename = expand_user_path($pass_req_filename);
if ( -e "$task_path/config/$pass_req_filename" ) {
$pass_req_file = "$task_path/config/$pass_req_filename";
} elsif ( -e "$vtr_flow_path/parse/pass_requirements/$pass_req_filename" ) {
$pass_req_file =
"$vtr_flow_path/parse/pass_requirements/$pass_req_filename";
} elsif ( -e $pass_req_filename ) {
$pass_req_file = $pass_req_filename;
}
if ( -e $pass_req_file ) {
$failed += check_pass_requirements($pass_req_file, $test_file_1, $test_file_2, $is_golden);
} else {
print "[ERROR] Cannot find pass_requirements_file. Checked for $task_path/config/$pass_req_filename or $vtr_flow_path/parse/$pass_req_filename or $pass_req_filename\n";
$failed += 1;
}
}
} else {
print
"[Warning] No 'pass_requirements_file' in task configuration file ($task_path/config/config.txt)\n";
}
if ($failed == 0) {
print "[Pass]\n";
}
return $failed;
}
sub check_pass_requirements() {
my ($pass_req_file, $test_file_1, $test_file_2, $is_golden) = @_;
my $line;
my @first_test_data;
my @second_test_data;
my @pass_req_data;
my @params;
my %type;
my %min_threshold;
my %max_threshold;
my %abs_diff_threshold;
my $failed = 0;
##############################################################
# Read files
##############################################################
if ( !-r $test_file_2 ) {
print "[ERROR] Failed to open $test_file_2: $!\n";
$failed += 1;
return $failed;
}
open( GOLDEN_DATA, "<$test_file_2" );
@second_test_data = <GOLDEN_DATA>;
close(GOLDEN_DATA);
if ( !-r $pass_req_file ) {
print "[ERROR] Failed to open $pass_req_file: $!\n";
$failed += 1;
return $failed;
}
@pass_req_data = load_file_with_includes($pass_req_file);
if ( !-r $test_file_1 ) {
print "[ERROR] Failed to open $test_file_1: $!\n";
$failed += 1;
return $failed;
}
open( TEST_DATA, "<$test_file_1" );
@first_test_data = <TEST_DATA>;
close(TEST_DATA);
##############################################################
# Process and check all parameters for consistency
##############################################################
my $second_test_params = shift @second_test_data;
my $first_test_params = shift @first_test_data;
my @second_test_params = split( /\t/, $second_test_params ); # get parameters of the second file results
my @first_test_params = split( /\t/, $first_test_params ); # get parameters of the first file results
my @second_test_params = map(trim($_), @second_test_params);
my @first_test_params = map(trim($_), @first_test_params);
my %first_params_index;
my $i = 0;
foreach my $param (@first_test_params) {
$first_params_index{$param} = $i;
$i++;
}
my %second_params_index;
$i = 0;
foreach my $param (@second_test_params) {
$second_params_index{$param} = $i;
$i++;
}
# Check to ensure all parameters to compare are consistent
foreach $line (@pass_req_data) {
# Ignore comments
if ( $line =~ /^\s*#.*$/ or $line =~ /^\s*$/ ) { next; }
my @data = split( /;/, $line );
my $name = trim( $data[0] );
my $check_arg = trim($data[1]);
my ($check_func) = $check_arg =~ m/(.*)\(/;
my ($check_func_args_str) = $check_arg =~ m/\((.*)\)/;
my @check_func_args = split( /,/, $check_func_args_str);
$type{$name} = trim($check_func);
if ( $check_func eq "Range" ) {
$min_threshold{$name} = trim( $check_func_args[0] );
$max_threshold{$name} = trim( $check_func_args[1] );
} elsif ($check_func eq "RangeAbs") {
$min_threshold{$name} = trim( $check_func_args[0] );
$max_threshold{$name} = trim( $check_func_args[1] );
$abs_diff_threshold{$name} = trim( $check_func_args[2] ); #Third element is absolute threshold
} elsif ($check_func eq "Equal") {
#Pass
} else {
print "[ERROR] $name has no valid comparison check specified (e.g. Range, RangeAbs, Equal) (was '$check_func').\n";
$failed += 1;
return $failed;
}
#Ensure item is in the first file
if (!exists $second_params_index{$name}) {
if ($is_golden){
print "[ERROR] $name is not in the golden results file.\n";
}else{
print "[ERROR] $name is not in the second parse file.\n";
}
$failed += 1;
}
# Ensure item is in new results
if (!exists $first_params_index{$name}) {
if ($is_golden){
print "[ERROR] $name is not in the results file.\n";
}else{
print "[ERROR] $name is not in the first parse file.\n";
}
$failed += 1;
}
push( @params, $name );
}
##############################################################
# Compare first file data data with second file data
##############################################################
if ( ( scalar @first_test_data ) != ( scalar @second_test_data ) ) {
print
"[ERROR] Different number of entries in the two files.\n";
$failed += 1;
}
# Iterate through each line of the test results data and compare with the golden data
foreach $line (@first_test_data) {
my @first_file_line = split( /\t/, $line );
my @second_file_line = split( /\t/, shift @second_test_data );
my $second_file_arch = trim(@second_file_line[$second_params_index{'arch'}]);
my $second_file_circuit = trim(@second_file_line[$second_params_index{'circuit'}]);
my $second_file_script_params = trim(@second_file_line[$second_params_index{'script_params'}]);
my $first_file_arch = trim(@first_file_line[$first_params_index{'arch'}]);
my $first_file_circuit = trim(@first_file_line[$first_params_index{'circuit'}]);
my $first_file_script_params = trim(@first_file_line[$first_params_index{'script_params'}]);
if ( ( $first_file_circuit ne $first_file_circuit )
or ( $first_file_arch ne $first_file_arch )
or ( $first_file_script_params ne $first_file_script_params )) {
if ($is_golden){
print "[ERROR] Circuit/Architecture/Script-Params mismatch between golden results ($second_file_arch/$second_file_circuit/$second_file_script_params) and result ($first_file_arch/$first_file_circuit/$first_file_script_params).\n";
} else{
print "[ERROR] Circuit/Architecture/Script-Params mismatch between first result file($second_file_arch/$second_file_circuit/$second_file_script_params) and second result file ($first_file_arch/$first_file_circuit/$first_file_script_params).\n";
}
$failed += 1;
return $failed;
}
my $circuitarch = "$first_file_arch/$first_file_circuit/$first_file_script_params";
# Check each parameter where the type determines what to check for
foreach my $value (@params) {
my $first_file_index = $first_params_index{$value};
my $second_file_index = $second_params_index{$value};
my $first_file_value = trim(@first_file_line[$first_file_index]);
my $second_file_value = trim(@second_file_line[$second_file_index]);
if ( $type{$value} eq "Range" or $type{$value} eq "RangeAbs" ) {
my $abs_diff = abs($first_file_value - $second_file_value);
my $ratio;
if ($second_file_value == 0) {
$ratio = "inf";
} else {
$ratio = $first_file_value / $second_file_value;
}
if($verbose) {
print "\tParam: $value\n";
print "\t\tTest: $first_file_value\n";
print "\t\tGolden Value: $second_file_value\n";
print "\t\tRatio: $ratio\n";
print "\t\tAbsDiff $abs_diff\n";
print "\t\tMinRatio $min_threshold{$value}\n";
print "\t\tMaxRatio $max_threshold{$value}\n";
print "\t\tAbsThreshold $abs_diff_threshold{$value}\n";
}
if ( exists $abs_diff_threshold{$value}
and $abs_diff <= $abs_diff_threshold{$value}) {
#Within absolute threshold
next;
}
if ( $ratio >= $min_threshold{$value}
and $ratio <= $max_threshold{$value}) {
#Within relative thershold
next;
}
if ($first_file_value == $second_file_value) {
#Equal (e.g. both zero)
next;
}
if ( $first_file_value eq 'nan'
and $second_file_value eq 'nan') {
#Both literal Not-a-Numbers
next;
}
#Beyond absolute and relative thresholds
if ($is_golden){
print
"[Fail] \n $circuitarch $value: golden = $second_file_value result = $first_file_value\n";
}else{
print
"[Fail] \n $circuitarch $value: first result = $first_file_value second result = $second_file_value\n";
}
$failed += 1;
} elsif ($type{$value} eq "Equal") {
if ( $first_file_value ne $second_file_value ) {
if ($is_golden) {
print "[Fail] \n $circuitarch $value: golden = $second_file_value result = $first_file_value\n";
} else {
print "[Fail] \n $circuitarch $value: first result = $first_file_value second result = $second_file_value\n";
}
$failed += 1;
}
} else {
# If the check type is unknown
$failed += 1;
print "[Fail] \n $circuitarch $value: unrecognized check type '$type{$value}' (e.g. Range, RangeAbs, Equal)\n";
}
}
}
return $failed;
}
sub trim() {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
sub expand_user_path {
my $str = shift;
$str =~ s/^~\//$ENV{"HOME"}\//;
return $str;
}
sub get_important_file {
my $task_path = shift;
my $vtr_flow_path = shift;
my $file = shift;
if ( -e "$task_path/config/$file" ) {
return "$task_path/config/$file";
}
elsif ( -e "$vtr_flow_path/parse/parse_config/$file" ) {
return "$vtr_flow_path/parse/parse_config/$file";
}
elsif ( -e "$vtr_flow_path/parse/qor_config/$file" ) {
return "$vtr_flow_path/parse/qor_config/$file";
}
elsif ( $file !~ /^\/.*/ ) {
die "Important file does not exist ($file)";
}
}
sub load_file_with_includes {
my ($filepath) = @_;
my @lines;
foreach my $line (load_file_lines($filepath)) {
if ($line =~ m/^\s*%include\s+"(.*)"\s*$/) {
#Assume the included file is in the same direcotry
my $include_filepath = File::Spec->catfile(dirname($filepath), $1);
$include_filepath = Cwd::realpath($include_filepath);
#Load it's lines, note that this is done recursively to resolve all includes
my @included_file_lines = load_file_with_includes($include_filepath);
push(@lines, "#Starting %include $include_filepath\n");
push(@lines, @included_file_lines);
push(@lines, "#Finished %include $include_filepath\n");
} else {
push(@lines, $line);
}
}
return @lines;
}
sub load_file_lines {
my ($filepath) = @_;
open(FILE, "<$filepath" ) or die("Failed to open file $filepath\n");
my @lines = <FILE>;
close(FILE);
return @lines;
}