| #!/usr/bin/env perl |
| |
| # runtest [options] FILENAME |
| # |
| # Read the file FILENAME. Each line contains a test. |
| # Convert template to test and crosstest. |
| # If possilble generate orphaned testversions, too. |
| # Use make to compile the test |
| |
| ################################################################################ |
| # Global configuration options for the runtestscript itself: |
| ################################################################################ |
| |
| # name of the global configuration file for the testsuite: |
| $config_file = "ompts.conf"; |
| $logfile = "ompts.log"; # overwriteable by value in config file |
| $env_set_threads_command = 'OMP_NUM_THREADS=%n; export OMP_NUM_THREADS;'; |
| $debug_mode = 0; |
| ################################################################################ |
| # After this line the script part begins! Do not edit anithing below |
| ################################################################################ |
| |
| |
| # Namespaces: |
| use Getopt::Long; |
| #use Unix::PID; |
| use Data::Dumper; |
| use ompts_parserFunctions; |
| |
| # Extracting given options |
| GetOptions("help", |
| "listlanguages", |
| "lang=s", |
| "list", |
| "testinfo=s", |
| "numthreads=i", |
| "test=s", |
| "compile!", |
| "run!", |
| "orphan!", |
| "resultfile=s" |
| ); |
| |
| # Get global configuratino options from config file: |
| if(! -e $config_file){ error ("Could not find config file $config_file\n", 1);} |
| open (CONFIG, "<$config_file") or error ("Could not open config file $config_file\n", 2); |
| while (<CONFIG>) { $config .= $_; } |
| close (CONFIG); |
| |
| ($logfile) = get_tag_values ("logfile", $config); |
| ($timeout) = get_tag_values ("singletesttimeout", $config); |
| ($display_errors) = get_tag_values("displayerrors", $config); |
| ($display_warnings) = get_tag_values ("displaywarnings", $config); |
| ($numthreads) = get_tag_values ("numthreads", $config); |
| ($env_set_threads_command) = get_tag_values("envsetthreadscommand",$config); |
| $env_set_threads_command =~ s/\%n/$numthreads/g; |
| @languages = get_tag_values ("language", $config); |
| |
| if (!defined($opt_compile)) {$opt_compile = 1;} |
| if (!defined($opt_run)) {$opt_run = 1;} |
| if (!defined($opt_orphan)) {$opt_orphan = 1;} |
| if (!defined($opt_resultsfile)) {($opt_resultsfile) = get_tag_values("resultsfile", $config);} |
| if ( defined($opt_numthreads) && ($opt_numthreads > 0)) {$numthreads = $opt_numthreads;} |
| if ($debug_mode) { |
| print <<EOF; |
| Testsuite configuration: |
| Logfile = $logfile |
| Timeout = $timeout seconds |
| Language: $opt_lang |
| Display errors: $display_errors |
| Display warnings: $display_warnings |
| Resultsfile: $opt_resultsfile |
| Numthreads: $numthreads |
| ------------------------------ |
| EOF |
| } |
| |
| $num_construcs = 0; |
| $num_tests = 0; |
| $num_failed_tests = 0; |
| $num_successful_tests = 0; |
| $num_verified_tests = 0; |
| $num_failed_compilation = 0; |
| |
| $num_normal_tests_failed = 0; |
| $num_normal_tests_compile_error = 0; |
| $num_normal_tests_timed_out = 0; |
| $num_normal_tests_successful = 0; |
| $num_normal_tests_verified = 0; |
| |
| $num_orphaned_tests_failed = 0; |
| $num_orphaned_tests_compile_error = 0; |
| $num_orphaned_tests_timed_out = 0; |
| $num_orphaned_tests_successful = 0; |
| $num_orphaned_tests_verified = 0; |
| |
| if ($opt_help) { print_help_text (); exit 0; } |
| if ($opt_listlanguages){ print_avail_langs (); exit 0; } |
| if ($opt_list) { print_avail_tests (); exit 0; } |
| if ($opt_testinfo) { print_testinfo (); exit 0; } |
| if ($opt_test) { write_result_file_head(); |
| execute_single_test (); exit 0; } |
| if (-e $ARGV[0]) { write_result_file_head(); |
| execute_testlist($ARGV[0]); print_results(); |
| result_summary(); exit 0;} |
| |
| ################################################################################ |
| # sub function definitions |
| ################################################################################ |
| |
| # Function which prints the results file |
| sub print_results |
| { |
| system("echo; cat $opt_resultsfile; echo;"); |
| } |
| |
| # Function which prints a summary of all test |
| sub result_summary |
| { |
| my $num_directives = @test_results; |
| |
| print <<EOF; |
| |
| Summary: |
| S Number of tested Open MP constructs: $num_constructs |
| S Number of used tests: $num_tests |
| S Number of failed tests: $num_failed_tests |
| S Number of successful tests: $num_successful_tests |
| S + from this were verified: $num_verified_tests |
| |
| Normal tests: |
| N Number of failed tests: $num_normal_tests_failed |
| N + from this fail compilation: $num_normal_tests_compile_error |
| N + from this timed out $num_normal_tests_timed_out |
| N Number of successful tests: $num_normal_tests_successful |
| N + from this were verified: $num_normal_tests_verified |
| |
| Orphaned tests: |
| O Number of failed tests: $num_orphaned_tests_failed |
| O + from this fail compilation: $num_orphaned_tests_compile_error |
| O + from this timed out $num_orphaned_tests_timed_out |
| O Number of successful tests: $num_orphaned_tests_successful |
| O + from this were verified: $num_orphaned_tests_verified |
| EOF |
| |
| } |
| |
| # Function that executest the tests specified in the given list |
| sub execute_testlist |
| { |
| my ($filename) = @_; |
| # opening testlist |
| open(TESTS,$filename) or error ("Could not open $filename\n", 1); |
| TEST: while (<TESTS>) { |
| if (/^\s*#/) {next TEST;} |
| if (/^\s*$/) {next TEST;} |
| $opt_test = $_; |
| chomp ($opt_test); |
| execute_single_test (); |
| } |
| # print Dumper(@test_results); |
| } |
| |
| # Function that executes a system command but takes care of the global timeout |
| # If command did not finish inbetween returns '-' otherwise the exit status of |
| # the system command |
| sub timed_sys_command |
| { |
| my ($command) = @_; |
| my $exit_status = '-'; |
| |
| # set up the timeout for the command |
| eval { |
| local $SIG{ALRM} = sub {die "alarm\n"}; |
| alarm $timeout; |
| log_message_add ("Starting command \"$command\""); |
| $exit_status = system ($command); |
| alarm 0; |
| }; |
| # check if command finished during the maximum execution time |
| if ($@ eq "alarm\n") { |
| # test timed out |
| # my $pid = Unix::PID->new(); |
| # $pid->get_pidof($command, 1); |
| # $pid->kill(); |
| if ($debug_mode) { |
| log_message_add ("Command \"$command\" reached max execution time.\n"); |
| } |
| return "TO"; |
| } |
| # test finished |
| return $exit_status; |
| } |
| |
| # Function that runs the tests given as a array containing the testnames |
| # Returns an array containing the percent values of the passed tests and the |
| # successful crosstests. |
| sub run_test |
| { |
| my ($testname, $orphan) = @_; |
| my $bin_name, $cbin_name; |
| my $cmd, $exit_status, $failed; |
| my $resulttest, $resultctest; |
| |
| # path to test and crosstest either in normal or in orphaned version |
| if ($orphan) { |
| $bin_name = "bin/$opt_lang/orph_test_$testname"; |
| $cbin_name = "bin/$opt_lang/orph_ctest_$testname"; |
| } else { |
| $bin_name = "bin/$opt_lang/test_$testname"; |
| $cbin_name = "bin/$opt_lang/ctest_$testname"; |
| } |
| # Check if executables exist |
| if (! -e $bin_name) { |
| test_error ("Could not find executable \"$bin_name\"."); |
| return ('test' => '-', 'crosstest' => '-'); |
| } |
| # run the test |
| $cmd = "$env_set_threads_command ./$bin_name >$bin_name.out"; |
| print "Running test with $numthreads threads ."; |
| $exit_status = timed_sys_command ($cmd); |
| ############################################################ |
| # Check if test finished within max execution time |
| if ($exit_status eq 'TO') { |
| print ".... failed (timeout)\n"; |
| return ('test' => 'TO', 'crosstest' => '-') |
| } |
| ############################################################ |
| # check if all tests were successful |
| $failed = $exit_status >> 8; |
| if ($failed < 0 or $failed > 100) { $failed = 100; } |
| $resulttest = 100 - $failed; |
| if ($resulttest eq 100) { |
| print ".... success ..."; |
| } else { |
| print ".... failed $failed\% of the tests\n"; |
| return ('test' => $resulttest, 'crosstest' => '-'); |
| } |
| ############################################################ |
| |
| # do crosstest |
| # check if executable exist |
| if (! -e $cbin_name) { |
| test_error ("Could not find executable \"$cbin_name\"."); |
| print "... not verified (crosstest missing)\n"; |
| return ('test' => $resulttest, 'crosstest' => '-'); |
| } |
| # run crosstest |
| # Test was successful, so it makes sense to run the crosstest |
| $cmd = "$env_set_threads_command ./$cbin_name > $cbin_name.out"; |
| $exit_status = timed_sys_command ($cmd); |
| ############################################################ |
| # Check if crosstest finished within max execution time |
| if ($exit_status eq 'TO') { |
| print "... not verified (timeout)\n"; |
| return ('test' => $result, 'crosstest' => 'TO'); |
| } |
| ############################################################ |
| # test if crosstests failed as expected |
| $resultctest = $exit_status >> 8; |
| if ($resultctest > 0) { |
| print "... and verified with $resultctest\% certainty\n"; |
| } else { |
| print "... but might be lucky\n"; |
| } |
| return ('test' => $resulttest, 'crosstest' => $resultctest); |
| ############################################################ |
| } |
| |
| # Function that generates the test binaries out of the sourcecode |
| sub compile_src |
| { |
| my ($testname, $orphan) = @_; |
| print "Compiling soures ............"; |
| if ($orphan) { |
| # Make orphaned tests |
| $exec_name = "bin/$opt_lang/orph_test_$testname"; |
| $crossexe_name = "bin/$opt_lang/orph_ctest_$testname"; |
| $resulttest = system ("make $exec_name > $exec_name\_compile.log" ); |
| $resultctest = system ("make $crossexe_name > $crossexe_name\_compile.log" ); |
| } else { |
| # Make test |
| $exec_name = "bin/$opt_lang/test_$testname"; |
| $crossexe_name = "bin/$opt_lang/ctest_$testname"; |
| $resulttest = system ("make $exec_name > $exec_name\_compile.log" ); |
| $resultctest = system ("make $crossexe_name > $crossexe_name\_compile.log" ); |
| } |
| if ($resulttest) { test_error ("Compilation of the test failed."); } |
| if ($resultctest){ test_error ("Compilation of the crosstest failed."); } |
| |
| if ($resulttest or $resultctest) { |
| print ".... failed\n"; |
| return 0; |
| } else { |
| print ".... success\n"; |
| return 1; |
| } |
| } |
| |
| # Function which prepare the directory structure: |
| sub init_directory_structure |
| { |
| my ($language) = @_; |
| if (-e "bin" && -d "bin") { warning ("Old binary directory detected!");} |
| else { system ("mkdir bin"); } |
| if (-e "bin/$language" && -d "bin/$language") { |
| warning ("Old binary directory for language $language found.");} |
| else { system ("mkdir bin/$language"); } |
| } |
| |
| # Function that generates the sourcecode for the given test |
| sub make_src |
| { |
| my ($testname, $orphan) = @_; |
| my $template_file; |
| my $src_name; |
| |
| $template_file = "$dir/$testname.$extension"; |
| if (!-e $template_file) { test_error ("Could not find template for \"$testname\""); } |
| |
| print "Generating sources .........."; |
| if ($orphan) { |
| # Make orphaned tests |
| $src_name = "bin/$opt_lang/orph_test_$testname.$extension"; |
| $resulttest = system ("./$templateparsername --test --orphan $template_file $src_name"); |
| $src_name = "bin/$opt_lang/orph_ctest_$testname.$extension"; |
| $resultctest = system ("./$templateparsername --crosstest --orphan $template_file $src_name"); |
| } else { |
| # Make test |
| $src_name = "bin/$opt_lang/test_$testname.$extension"; |
| $resulttest = system ("./$templateparsername --test --noorphan $template_file $src_name"); |
| $src_name = "bin/$opt_lang/ctest_$testname.$extension"; |
| $resultctest = system ("./$templateparsername --crosstest --noorphan $template_file $src_name"); |
| } |
| if ($resulttest) { test_error ("Generation of sourcecode for the test failed."); } |
| if ($resultctest){ test_error ("Generation of sourcecode for the crosstest failed."); } |
| |
| if ($resulttest or $resultctest) { |
| print ".... failed\n"; |
| return 0; |
| } else { |
| print ".... success\n"; |
| return 1; |
| } |
| } |
| |
| # Function which checks if a given test is orphanable |
| sub test_is_orphanable |
| { |
| my ($testname) = @_; |
| my $src; |
| my $file = "$dir/$testname.$extension"; |
| if(! -e $file){ test_error ("Could not find test file $file\n");} |
| open (TEST, "<$file") or test_error ("Could not open test file $file\n"); |
| while (<TEST>) { $src .= $_; } |
| close (TEST); |
| return $src =~/ompts:orphan/; |
| } |
| |
| sub write_result_file_head |
| { |
| open (RESULTS, ">$opt_resultsfile") or error ("Could not open file '$opt_resultsfile' to write results.", 1); |
| $resultline = sprintf "%-25s %-s\n", "#Tested Directive", "\tt\tct\tot\toct"; |
| print RESULTS $resultline; |
| } |
| |
| # Function which adds a result to the list of results |
| sub add_result |
| { |
| my ($testname, $result) = @_; |
| # print Dumper(@{$result}); |
| |
| $num_constructs++; |
| |
| open (RESULTS, ">>$opt_resultsfile") or error ("Could not open file '$opt_resultsfile' to write results.", 1); |
| |
| if (${$result}[0][0]) { |
| $num_tests ++;} |
| |
| if ($opt_compile and ${$result}[0][1] eq 0) { |
| ${$result}[0][2]{test} = 'ce'; |
| ${$result}[0][2]{crosstest} = '-'; |
| $num_normal_tests_compile_error++; |
| $num_normal_tests_failed++; |
| } |
| |
| if ($opt_run and ${$result}[0][2] and ${$result}[0][2]{test} ne 'ce') { |
| if (${$result}[0][2]{test} == 100) { |
| $num_normal_tests_successful++; |
| if (${$result}[0][2]{crosstest} == 100){ |
| $num_normal_tests_verified++;} |
| } elsif (${$result}[0][2]{test} eq 'TO'){ |
| $num_normal_tests_timed_out++; |
| $num_normal_tests_failed++; |
| } else { |
| $num_normal_tests_failed++; |
| } |
| } |
| $resultline = "${$result}[0][2]{test}\t${$result}[0][2]{crosstest}\t"; |
| |
| if (${$result}[1][0]) { |
| $num_tests ++;} |
| else { $resultline .= "-\t-\n"; } |
| |
| if ($opt_compile and ${$result}[1][1] eq 0) { |
| ${$result}[1][2]{test} = 'ce'; |
| ${$result}[1][2]{crosstest} = '-'; |
| $num_orphaned_tests_compile_error++; |
| $num_orphaned_tests_failed++; |
| } |
| |
| if ($opt_run and ${$result}[1][2] and ${$result}[1][2]{test} ne 'ce') { |
| if (${$result}[1][2]{test} == 100) { |
| $num_orphaned_tests_successful++; |
| if (${$result}[1][2]{crosstest} == 100){ |
| $num_orphaned_tests_verified++;} |
| } elsif (${$result}[1][2]{test} eq 'TO'){ |
| $num_orphaned_tests_timed_out++; |
| $num_orphaned_tests_failed++; |
| } else { |
| $num_orphaned_tests_failed++; |
| } |
| } |
| $resultline .= "${$result}[1][2]{test}\t${$result}[1][2]{crosstest}\n"; |
| |
| $num_failed_tests = $num_normal_tests_failed + $num_orphaned_tests_failed; |
| $num_failed_compilation = $num_normal_tests_compile_error + $num_orphaned_tests_compile_error; |
| $num_successful_tests = $num_normal_tests_successful + $num_orphaned_tests_successful; |
| $num_verified_tests = $num_normal_tests_verified + $num_orphaned_tests_verified; |
| |
| $resultline2 = sprintf "%-25s %-s", "$testname", "\t$resultline"; |
| print RESULTS $resultline2; |
| } |
| |
| # Function which executes a single test |
| sub execute_single_test |
| { |
| my @result; |
| init_language_settings ($opt_lang); |
| init_directory_structure ($opt_lang); |
| log_message_add ("Testing for \"$opt_test\":"); |
| print "Testing for \"$opt_test\":\n"; |
| # tests in normal mode |
| if ($opt_compile){ $result[0][0] = make_src ($opt_test, 0); |
| $result[0][1] = compile_src ($opt_test, 0);} |
| if ($opt_run && $result[0][1] == 1) { |
| $result[0][2] = {run_test ($opt_test, 0)};} |
| # tests in orphaned mode |
| if ($opt_orphan && test_is_orphanable($opt_test)){ |
| log_message_add ("Testing for \"$opt_test\" in orphaned mode:"); |
| print "+ orphaned mode:\n"; |
| if ($opt_compile) { $result[1][0] = make_src ($opt_test, 1); |
| $result[1][1] = compile_src ($opt_test, 1);} |
| if ($opt_run && $result[1][1] == 1) { |
| $result[1][2] = {run_test ($opt_test, 1)};} |
| } |
| add_result($opt_test, \@result); |
| } |
| |
| # Function that prints info about a given test |
| sub print_testinfo |
| { |
| init_language_settings($opt_lang); |
| my $doc = ""; |
| my $file = $dir."/".$opt_testinfo.".".$extension; |
| if (! -e $file) {error ("Could not find template for test $opt_testinfo", 5);} |
| open (TEST,"<$file") or error ("Could not open template file \"$file\" for test $opt_testinfo", 6); |
| while (<TEST>) {$doc .= $_;} |
| close (TEST); |
| |
| (my $omp_version) = get_tag_values ("ompts:ompversion", $doc); |
| (my $dependences) = get_tag_values ("ompts:dependences", $doc); |
| (my $description) = get_tag_values ("ompts:testdescription", $doc); |
| my $orphanable = 'no'; |
| if ($doc =~ /ompts:orphan/) {$orphanable = 'yes';} |
| print <<EOF; |
| Info for test $opt_testinfo: |
| Open MP standard: $omp_version |
| Orphaned mode: $orphanable |
| Dependencies: $dependences |
| Description: $description |
| EOF |
| } |
| |
| # Function that initializes the settings for the given language |
| sub init_language_settings |
| { |
| my ($language) = @_; |
| foreach my $lang (@languages) { |
| (my $name) = get_tag_values ("languagename", $lang); |
| if ($name eq $language) { |
| ($extension) = get_tag_values ("fileextension", $lang); |
| ($dir) = get_tag_values ("dir", $lang); |
| ($templateparsername) = get_tag_values ("templateparsername", $lang); |
| last; |
| } |
| } |
| # Check if we found the specified language in the config file |
| if (!$extension and !$dir) { |
| error ("Language $language could not be found.\n", 3); |
| } |
| } |
| |
| |
| |
| # Function that prints all available tests for the given language |
| sub print_avail_tests |
| { |
| init_language_settings($opt_lang); |
| my @tests; |
| opendir(DIR,"$dir") or error ("Could not open directory $dir", 4); |
| while($_ = readdir(DIR)) { if (/\.$extension$/) {s/\.$extension//; push (@tests, $_);}} |
| closedir(DIR); |
| print "Found ".(@tests)." tests:\n". "-" x 30 . "\n"; |
| foreach (@tests) { print $_."\n";} |
| } |
| |
| # Function that prints all available tests for the given language |
| sub print_avail_langs |
| { |
| if (@languages > 0) { |
| print "Available languages:\n"; |
| foreach (@languages) { |
| (my $name) = get_tag_values ("languagename", $_); |
| print "$name\n"; |
| } |
| } else { |
| print "No languages available\n"; |
| } |
| } |
| |
| # Function that prints the error message |
| sub print_help_text |
| { |
| print <<EOF; |
| runtest.pl [options] [FILE] |
| |
| Executes the tests listed in FILE. FILE has to contain the names of the tests, |
| one test per line. Lines starting with '#' will be ignored. |
| A language has to be specified for all commands except --help and --listlanguages. |
| |
| Options: |
| --help displays this help message |
| --listlanguages lists all available languages |
| --lang=s select language |
| --list list available tests for a language |
| --testinfo=NAME show info for test NAME |
| --numthreads=NUM set number of threads (overwrites config file settings) |
| --test=NAME execute single test NAME |
| --nocompile do not compile tests |
| --norun do not run tests |
| --noorphan switch of orphaned tests |
| --resultfile=NAME use NAME as resultfile (overwrites config file settings) |
| EOF |
| } |
| |
| # Function that writes an error message for a failed test / part of a test |
| sub test_error |
| { |
| my ($message) = @_; |
| log_message_add ("ERROR: $message"); |
| if ($display_errors eq 1) { print STDERR "ERROR: $message\n"; } |
| } |
| |
| # Function that returns an warning message |
| sub warning { |
| my ($message) = @_; |
| if ($display_warnings eq 1) { print "Warniong: $message\n"; } |
| log_message_add ("Warning: $message"); |
| } |
| |
| # Function that returns an error message and exits with the specified error code |
| sub error { |
| my ($message, $error_code) = @_; |
| if ($display_errors eq 1) { print STDERR "ERROR: $message\n"; } |
| log_message_add ("ERROR: $message"); |
| exit ($error_code); |
| } |
| |
| # Function which adds an new entry into the logfile together with a timestamp |
| sub log_message_add |
| { |
| (my $message) = @_; |
| ($sec,$min,$hour,$mday,$mon,$year,$wday,$ydat,$isdst) = localtime(); |
| if(length($hour) == 1) { $hour="0$hour"; } |
| if(length($min) == 1) { $min="0$min"; } |
| if(length($sec) == 1) { $sec="0$sec"; } |
| $mon=$mon+1; |
| $year=$year+1900; |
| open (LOGFILE,">>$logfile") or die "ERROR: Could not create $logfile\n"; |
| print LOGFILE "$mday/$mon/$year $hour.$min.$sec: $message\n"; |
| } |