Merge remote-tracking branch 'upstream/master' into sta_update_upstream_lvf_stuff
This commit is contained in:
commit
5ce29f4d7d
|
|
@ -4,6 +4,13 @@ OpenSTA Timing Analyzer Release Notes
|
||||||
This file summarizes user visible changes for each release.
|
This file summarizes user visible changes for each release.
|
||||||
See ApiChangeLog.txt for changes to the STA api.
|
See ApiChangeLog.txt for changes to the STA api.
|
||||||
|
|
||||||
|
2026/03/23
|
||||||
|
----------
|
||||||
|
|
||||||
|
The write_path_spice command -spice_directory has been changed to
|
||||||
|
-spice_file, which is a prefix for the spice filenames. Successive
|
||||||
|
paths are written in files name <spice_file>_<path_number>.sp.
|
||||||
|
|
||||||
Release 3.0.1 2026/03/12
|
Release 3.0.1 2026/03/12
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
|
|
|
||||||
3453
doc/OpenSTA.fodt
3453
doc/OpenSTA.fodt
File diff suppressed because it is too large
Load Diff
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -25,7 +25,7 @@
|
||||||
namespace eval sta {
|
namespace eval sta {
|
||||||
|
|
||||||
define_cmd_args "write_path_spice" { -path_args path_args\
|
define_cmd_args "write_path_spice" { -path_args path_args\
|
||||||
-spice_directory spice_directory\
|
-spice_file spice_file\
|
||||||
-lib_subckt_file lib_subckts_file\
|
-lib_subckt_file lib_subckts_file\
|
||||||
-model_file model_file\
|
-model_file model_file\
|
||||||
-power power\
|
-power power\
|
||||||
|
|
@ -34,12 +34,13 @@ define_cmd_args "write_path_spice" { -path_args path_args\
|
||||||
|
|
||||||
proc write_path_spice { args } {
|
proc write_path_spice { args } {
|
||||||
parse_key_args "write_path_spice" args \
|
parse_key_args "write_path_spice" args \
|
||||||
keys {-spice_directory -lib_subckt_file -model_file \
|
keys {-spice_file -lib_subckt_file -model_file \
|
||||||
-power -ground -path_args -simulator} \
|
-power -ground -path_args -simulator} \
|
||||||
flags {}
|
flags {}
|
||||||
|
|
||||||
if { [info exists keys(-spice_directory)] } {
|
if { [info exists keys(-spice_file)] } {
|
||||||
set spice_dir [file nativename $keys(-spice_directory)]
|
set spice_file [file nativename $keys(-spice_file)]
|
||||||
|
set spice_dir [file dirname $spice_file]
|
||||||
if { ![file exists $spice_dir] } {
|
if { ![file exists $spice_dir] } {
|
||||||
sta_error 1920 "Directory $spice_dir not found."
|
sta_error 1920 "Directory $spice_dir not found."
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +51,7 @@ proc write_path_spice { args } {
|
||||||
sta_error 1922 "Cannot write in $spice_dir."
|
sta_error 1922 "Cannot write in $spice_dir."
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sta_error 1923 "No -spice_directory specified."
|
sta_error 1923 "No -spice_file specified."
|
||||||
}
|
}
|
||||||
|
|
||||||
if { [info exists keys(-lib_subckt_file)] } {
|
if { [info exists keys(-lib_subckt_file)] } {
|
||||||
|
|
@ -96,10 +97,10 @@ proc write_path_spice { args } {
|
||||||
set path_index 1
|
set path_index 1
|
||||||
foreach path_end $path_ends {
|
foreach path_end $path_ends {
|
||||||
set path [$path_end path]
|
set path [$path_end path]
|
||||||
set path_name "path_$path_index"
|
set path_file "${spice_file}_$path_index"
|
||||||
set spice_file [file join $spice_dir "$path_name.sp"]
|
set spice_file1 ${path_file}.sp
|
||||||
set subckt_file [file join $spice_dir "$path_name.subckt"]
|
set subckt_file ${path_file}.subckt
|
||||||
write_path_spice_cmd $path $spice_file $subckt_file \
|
write_path_spice_cmd $path $spice_file1 $subckt_file \
|
||||||
$lib_subckt_file $model_file $power $ground $ckt_sim
|
$lib_subckt_file $model_file $power $ground $ckt_sim
|
||||||
incr path_index
|
incr path_index
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,8 @@
|
||||||
#
|
#
|
||||||
# This notice may not be removed or altered from any source distribution.
|
# This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
# regression -help | [-threads threads] [-valgrind] [-report_stats] test1 [test2...]
|
# Usage: regression -help | [-threads threads] [-j jobs] [-valgrind] [-report_stats]
|
||||||
|
# test1 [test2...]
|
||||||
|
|
||||||
proc regression_main {} {
|
proc regression_main {} {
|
||||||
setup
|
setup
|
||||||
|
|
@ -41,12 +42,13 @@ proc regression_main {} {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc setup {} {
|
proc setup {} {
|
||||||
global result_dir diff_file failure_file errors
|
global result_dir diff_file failure_file errors failed_tests
|
||||||
global use_valgrind valgrind_shared_lib_failure
|
global use_valgrind valgrind_shared_lib_failure
|
||||||
global report_stats
|
global report_stats max_jobs app_path
|
||||||
|
|
||||||
set use_valgrind 0
|
set use_valgrind 0
|
||||||
set report_stats 0
|
set report_stats 0
|
||||||
|
set max_jobs 1
|
||||||
|
|
||||||
if { !([file exists $result_dir] && [file isdirectory $result_dir]) } {
|
if { !([file exists $result_dir] && [file isdirectory $result_dir]) } {
|
||||||
file mkdir $result_dir
|
file mkdir $result_dir
|
||||||
|
|
@ -60,20 +62,28 @@ proc setup {} {
|
||||||
set errors(fail) 0
|
set errors(fail) 0
|
||||||
set errors(no_cmd) 0
|
set errors(no_cmd) 0
|
||||||
set errors(no_ok) 0
|
set errors(no_ok) 0
|
||||||
|
set failed_tests {}
|
||||||
set valgrind_shared_lib_failure 0
|
set valgrind_shared_lib_failure 0
|
||||||
|
|
||||||
|
if { ![file exists $app_path] } {
|
||||||
|
error "$app_path not found."
|
||||||
|
} elseif { ![file executable $app_path] } {
|
||||||
|
error "$app_path is not executable."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc parse_args {} {
|
proc parse_args {} {
|
||||||
global argv app_options tests test_groups cmd_paths
|
global argv app_options tests test_groups cmd_paths
|
||||||
global use_valgrind
|
global use_valgrind
|
||||||
global result_dir tests
|
global result_dir tests
|
||||||
global report_stats
|
global report_stats max_jobs
|
||||||
|
|
||||||
while { $argv != {} } {
|
while { $argv != {} } {
|
||||||
set arg [lindex $argv 0]
|
set arg [lindex $argv 0]
|
||||||
if { $arg == "help" || $arg == "-help" } {
|
if { $arg == "help" || $arg == "-help" } {
|
||||||
puts {Usage: regression [-help] [-threads threads] [-valgrind] [-report_stats] tests...}
|
puts {Usage: regression [-help] [-threads threads] [-j jobs] [-valgrind] [-report_stats] tests...}
|
||||||
puts " -threads max|integer - number of threads to use"
|
puts " -threads max|integer - number of threads to use"
|
||||||
|
puts " -j jobs - number of parallel jobs (processes) to run"
|
||||||
puts " -valgrind - run valgrind (linux memory checker)"
|
puts " -valgrind - run valgrind (linux memory checker)"
|
||||||
puts " -report_stats - report run time and memory"
|
puts " -report_stats - report run time and memory"
|
||||||
puts " Wildcarding for test names is supported (enclose in \"'s)"
|
puts " Wildcarding for test names is supported (enclose in \"'s)"
|
||||||
|
|
@ -90,6 +100,14 @@ proc parse_args {} {
|
||||||
lappend app_options "-threads"
|
lappend app_options "-threads"
|
||||||
lappend app_options $threads
|
lappend app_options $threads
|
||||||
set argv [lrange $argv 2 end]
|
set argv [lrange $argv 2 end]
|
||||||
|
} elseif { $arg == "-j" } {
|
||||||
|
set jobs [lindex $argv 1]
|
||||||
|
if { ![string is integer $jobs] || $jobs < 1 } {
|
||||||
|
puts "Error: -j arg $jobs must be a positive integer."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
set max_jobs $jobs
|
||||||
|
set argv [lrange $argv 2 end]
|
||||||
} elseif { $arg == "-valgrind" } {
|
} elseif { $arg == "-valgrind" } {
|
||||||
if { ![find_valgrind] } {
|
if { ![find_valgrind] } {
|
||||||
error "valgrind not found."
|
error "valgrind not found."
|
||||||
|
|
@ -149,98 +167,226 @@ proc expand_tests { argv } {
|
||||||
}
|
}
|
||||||
|
|
||||||
proc run_tests {} {
|
proc run_tests {} {
|
||||||
global tests errors app_path
|
global tests errors app_path max_jobs
|
||||||
|
|
||||||
|
if { $max_jobs > 1 } {
|
||||||
|
run_tests_parallel
|
||||||
|
} else {
|
||||||
foreach test $tests {
|
foreach test $tests {
|
||||||
run_test $test
|
run_test $test
|
||||||
}
|
}
|
||||||
# Macos debug info generated by valgrind.
|
}
|
||||||
file delete -force "$app_path.dSYM"
|
write_failure_file
|
||||||
|
write_diff_file
|
||||||
}
|
}
|
||||||
|
|
||||||
proc run_test { test } {
|
proc run_test { test } {
|
||||||
global result_dir diff_file errors diff_options report_stats
|
global result_dir diff_file errors diff_options
|
||||||
|
|
||||||
set cmd_file [test_cmd_file $test]
|
puts -nonewline $test
|
||||||
if [file exists $cmd_file] {
|
flush stdout
|
||||||
set ok_file [test_ok_file $test]
|
set exit_code 0
|
||||||
|
if { [test_cmd_file_exists $test] } {
|
||||||
|
set cmd [make_cmd_file $test]
|
||||||
set log_file [test_log_file $test]
|
set log_file [test_log_file $test]
|
||||||
|
if { [catch [concat "exec" "$cmd >& $log_file"] result result_options] } {
|
||||||
|
set details [dict get $result_options -errorcode]
|
||||||
|
set exit_signal [lindex $details 2]
|
||||||
|
if { $exit_signal == "SIGSEGV" } {
|
||||||
|
set exit_code 139
|
||||||
|
} else {
|
||||||
|
set exit_code 128
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
puts " [test_status $test $exit_code]"
|
||||||
|
}
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# Parallel runs use one pipeline per test; close() yields the real exit status.
|
||||||
|
# (Non-blocking channels must be switched to blocking before close - see Tcl manual.)
|
||||||
|
proc regression_parallel_close_pipe { fh } {
|
||||||
|
fconfigure $fh -blocking 1
|
||||||
|
if { [catch {close $fh} err opts] } {
|
||||||
|
set ec [dict get $opts -errorcode]
|
||||||
|
if { [lindex $ec 0] == "CHILDSTATUS" } {
|
||||||
|
return [lindex $ec 2]
|
||||||
|
}
|
||||||
|
return 128
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
proc regression_pipe_readable { fh test } {
|
||||||
|
global reg_parallel_active reg_parallel_job_done
|
||||||
|
|
||||||
|
read $fh
|
||||||
|
if { [eof $fh] } {
|
||||||
|
fileevent $fh readable {}
|
||||||
|
set exit_code [regression_parallel_close_pipe $fh]
|
||||||
|
puts "$test [test_status $test $exit_code]"
|
||||||
|
incr reg_parallel_active -1
|
||||||
|
incr reg_parallel_job_done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc open_test_pipeline { test } {
|
||||||
|
set cmd [make_cmd_file $test]
|
||||||
|
set log [test_log_file $test]
|
||||||
|
set inner [format {%s > %s 2>&1} $cmd [file nativename $log]]
|
||||||
|
set fh [open [format {|/bin/sh -c %s} [list $inner]] r]
|
||||||
|
fconfigure $fh -blocking 0
|
||||||
|
return $fh
|
||||||
|
}
|
||||||
|
|
||||||
|
proc run_tests_parallel {} {
|
||||||
|
global tests max_jobs reg_parallel_active reg_parallel_job_done
|
||||||
|
|
||||||
|
set reg_parallel_active 0
|
||||||
|
set reg_parallel_job_done 0
|
||||||
|
set test_idx 0
|
||||||
|
set test_count [llength $tests]
|
||||||
|
|
||||||
|
while { $test_idx < $test_count || $reg_parallel_active > 0 } {
|
||||||
|
while { $reg_parallel_active < $max_jobs && $test_idx < $test_count } {
|
||||||
|
set test [lindex $tests $test_idx]
|
||||||
|
incr test_idx
|
||||||
|
if { ![test_cmd_file_exists $test] } {
|
||||||
|
puts -nonewline $test
|
||||||
|
flush stdout
|
||||||
|
puts " [test_status $test 0]"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
set fh [open_test_pipeline $test]
|
||||||
|
fileevent $fh readable [list regression_pipe_readable $fh $test]
|
||||||
|
incr reg_parallel_active
|
||||||
|
}
|
||||||
|
if { $reg_parallel_active > 0 } {
|
||||||
|
set before $reg_parallel_job_done
|
||||||
|
while { $reg_parallel_job_done == $before } {
|
||||||
|
vwait reg_parallel_job_done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proc make_cmd_file { test } {
|
||||||
|
global app_path app_options result_dir use_valgrind report_stats
|
||||||
|
|
||||||
foreach file [glob -nocomplain [file join $result_dir $test.*]] {
|
foreach file [glob -nocomplain [file join $result_dir $test.*]] {
|
||||||
file delete -force $file
|
file delete -force $file
|
||||||
}
|
}
|
||||||
puts -nonewline $test
|
|
||||||
flush stdout
|
|
||||||
set test_errors [run_test_app $test $cmd_file $log_file]
|
|
||||||
if { [lindex $test_errors 0] == "ERROR" } {
|
|
||||||
puts " *ERROR* [lrange $test_errors 1 end]"
|
|
||||||
append_failure $test
|
|
||||||
incr errors(error)
|
|
||||||
|
|
||||||
# For some reason seg faults aren't echoed in the log - add them.
|
set cmd_file [test_cmd_file $test]
|
||||||
if { [llength $test_errors] > 1 && [file exists $log_file] } {
|
set ok_file [test_ok_file $test]
|
||||||
set log_ch [open $log_file "a"]
|
set log_file [test_log_file $test]
|
||||||
puts $log_ch $test_errors
|
|
||||||
close $log_ch
|
|
||||||
}
|
|
||||||
|
|
||||||
# Report partial log diff anyway.
|
set run_file [test_run_file $test]
|
||||||
if [file exists $ok_file] {
|
set run_stream [open $run_file "w"]
|
||||||
catch [concat exec diff $diff_options $ok_file $log_file \
|
puts $run_stream "cd [file dirname $cmd_file]"
|
||||||
>> $diff_file]
|
puts $run_stream "include [file tail $cmd_file]"
|
||||||
}
|
if { $use_valgrind } {
|
||||||
} else {
|
puts $run_stream "sta::delete_all_memory"
|
||||||
set error_msg ""
|
|
||||||
if { [lsearch $test_errors "MEMORY"] != -1 } {
|
|
||||||
append error_msg " *MEMORY*"
|
|
||||||
append_failure $test
|
|
||||||
incr errors(memory)
|
|
||||||
}
|
|
||||||
if { [lsearch $test_errors "LEAK"] != -1 } {
|
|
||||||
append error_msg " *LEAK*"
|
|
||||||
append_failure $test
|
|
||||||
incr errors(leak)
|
|
||||||
}
|
}
|
||||||
if { $report_stats } {
|
if { $report_stats } {
|
||||||
append error_msg " [test_stats_summary $test]"
|
puts $run_stream "sta::write_stats [test_stats_file $test]"
|
||||||
|
}
|
||||||
|
close $run_stream
|
||||||
|
|
||||||
|
if { $use_valgrind } {
|
||||||
|
global valgrind_options
|
||||||
|
set cmd "valgrind $valgrind_options $app_path $app_options $run_file"
|
||||||
|
} else {
|
||||||
|
set cmd "$app_path $app_options $run_file"
|
||||||
|
}
|
||||||
|
return $cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
if [file exists $ok_file] {
|
proc test_cmd_file_exists { test } {
|
||||||
# Filter dos '/r's from log file.
|
set cmd_file [test_cmd_file $test]
|
||||||
set tmp_file [file join $result_dir $test.tmp]
|
return [file exists $cmd_file]
|
||||||
exec tr -d "\r" < $log_file > $tmp_file
|
|
||||||
file rename -force $tmp_file $log_file
|
|
||||||
if [catch [concat exec diff $diff_options $ok_file $log_file \
|
|
||||||
>> $diff_file]] {
|
|
||||||
puts " *FAIL*$error_msg"
|
|
||||||
append_failure $test
|
|
||||||
incr errors(fail)
|
|
||||||
} else {
|
|
||||||
puts " pass$error_msg"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
puts " *NO OK FILE*"
|
|
||||||
append_failure $test
|
|
||||||
incr errors(no_ok)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
puts "$test *NO CMD FILE*"
|
|
||||||
incr errors(no_cmd)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proc test_stats { test } {
|
proc test_status { test exit_code } {
|
||||||
if { ![catch {open [test_stats_file $test] r} stream] } {
|
global result_dir diff_options errors
|
||||||
gets $stream line1
|
global use_valgrind report_stats test_status
|
||||||
close $stream
|
|
||||||
return $line1
|
set test_status {}
|
||||||
|
if { ![test_cmd_file_exists $test] } {
|
||||||
|
test_failed $test "no_cmd"
|
||||||
} else {
|
} else {
|
||||||
return {}
|
set log_file [test_log_file $test]
|
||||||
|
|
||||||
|
if { [file exists $log_file] } {
|
||||||
|
# Check log file for error patterns
|
||||||
|
set log_ch [open $log_file "r"]
|
||||||
|
set log_content [read $log_ch]
|
||||||
|
close $log_ch
|
||||||
|
|
||||||
|
# Check if exit code indicates a segfault or signal termination
|
||||||
|
# Exit codes >= 128 typically indicate termination by a signal
|
||||||
|
# 139 = 128 + 11 (SIGSEGV), 134 = 128 + 6 (SIGABRT), etc.
|
||||||
|
if { $exit_code >= 128
|
||||||
|
|| [string match "*Segmentation fault*" $log_content] \
|
||||||
|
|| [string match "*DEADLYSIGNAL*" $log_content] \
|
||||||
|
|| [string match "*Abort*" $log_content] \
|
||||||
|
|| [string match "*Fatal*" $log_content] } {
|
||||||
|
test_failed $test "error"
|
||||||
|
} elseif { [string match "*heap-use-after-free*" $log_content] } {
|
||||||
|
# ASAN error
|
||||||
|
test_failed $test "memory"
|
||||||
}
|
}
|
||||||
|
set ok_file [test_ok_file $test]
|
||||||
|
if { [file exists $ok_file] } {
|
||||||
|
if { $use_valgrind } {
|
||||||
|
cleanse_valgrind_logfile $test
|
||||||
|
}
|
||||||
|
if { [catch [concat exec diff $diff_options $ok_file $log_file]] } {
|
||||||
|
if { $test_status == "" } {
|
||||||
|
test_failed $test "fail"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if { $test_status == "" } {
|
||||||
|
test_failed $test "no_ok"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Log file doesn't exist, likely an error
|
||||||
|
test_failed $test "error" "*ERROR* no log file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if { $test_status == {} } {
|
||||||
|
append test_status "pass"
|
||||||
|
}
|
||||||
|
if { $report_stats } {
|
||||||
|
append test_status " [test_stats_summary $test]"
|
||||||
|
}
|
||||||
|
return $test_status
|
||||||
|
}
|
||||||
|
|
||||||
|
proc test_exit_code { test } {
|
||||||
|
# Read exit code
|
||||||
|
set test_error ""
|
||||||
|
set exit_code_file [test_exit_code_file $test]
|
||||||
|
if { [file exists $exit_code_file] } {
|
||||||
|
set exit_code_ch [open $exit_code_file "r"]
|
||||||
|
set exit_code [string trim [read $exit_code_ch]]
|
||||||
|
close $exit_code_ch
|
||||||
|
|
||||||
|
if { [string is integer $exit_code] } {
|
||||||
|
return $exit_code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
proc test_stats_summary { test } {
|
proc test_stats_summary { test } {
|
||||||
set stats [test_stats $test]
|
if { ![catch {open [test_stats_file $test] r} stream] } {
|
||||||
|
gets $stream stats
|
||||||
|
close $stream
|
||||||
|
|
||||||
set elapsed_time [lindex $stats 0]
|
set elapsed_time [lindex $stats 0]
|
||||||
set user_time [lindex $stats 1]
|
set user_time [lindex $stats 1]
|
||||||
set memory [lindex $stats 2]
|
set memory [lindex $stats 2]
|
||||||
|
|
@ -260,83 +406,51 @@ proc test_stats_summary { test } {
|
||||||
set mem "?"
|
set mem "?"
|
||||||
}
|
}
|
||||||
return "$elapsed $user $mem"
|
return "$elapsed $user $mem"
|
||||||
}
|
|
||||||
|
|
||||||
proc append_failure { test } {
|
|
||||||
global failure_file
|
|
||||||
set fail_ch [open $failure_file "a"]
|
|
||||||
puts $fail_ch $test
|
|
||||||
close $fail_ch
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return error.
|
|
||||||
proc run_test_app { test cmd_file log_file } {
|
|
||||||
global app_path errorCode use_valgrind
|
|
||||||
if { $use_valgrind } {
|
|
||||||
return [run_test_valgrind $test $cmd_file $log_file]
|
|
||||||
} else {
|
} else {
|
||||||
return [run_test_plain $test $cmd_file $log_file]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
proc run_test_plain { test cmd_file log_file } {
|
|
||||||
global app_path app_options result_dir errorCode
|
|
||||||
global report_stats
|
|
||||||
|
|
||||||
if { ![file exists $app_path] } {
|
|
||||||
return "ERROR $app_path not found."
|
|
||||||
} elseif { ![file executable $app_path] } {
|
|
||||||
return "ERROR $app_path is not executable."
|
|
||||||
} else {
|
|
||||||
set run_file [test_run_file $test]
|
|
||||||
set run_stream [open $run_file "w"]
|
|
||||||
puts $run_stream "cd [file dirname $cmd_file]"
|
|
||||||
puts $run_stream "include [file tail $cmd_file]"
|
|
||||||
if { $report_stats } {
|
|
||||||
set stat_file [file normalize [test_stats_file $test]]
|
|
||||||
puts $run_stream "sta::write_stats $stat_file"
|
|
||||||
}
|
|
||||||
close $run_stream
|
|
||||||
|
|
||||||
if { [catch [concat exec $app_path $app_options $run_file >& $log_file]] } {
|
|
||||||
set signal [lindex $errorCode 2]
|
|
||||||
set error [lindex $errorCode 3]
|
|
||||||
# Error strings are not consistent across platforms but signal
|
|
||||||
# names are.
|
|
||||||
if { $signal == "SIGSEGV" } {
|
|
||||||
# Save corefiles to regression results directory.
|
|
||||||
set pid [lindex $errorCode 1]
|
|
||||||
set sys_corefile [test_sys_core_file $test $pid]
|
|
||||||
if { [file exists $sys_corefile] } {
|
|
||||||
file copy $sys_corefile [test_core_file $test]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "ERROR $error"
|
|
||||||
}
|
|
||||||
file delete $run_file
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc run_test_valgrind { test cmd_file log_file } {
|
proc test_failed { test reason } {
|
||||||
global app_path app_options valgrind_options result_dir errorCode
|
global errors test_status failed_tests
|
||||||
|
|
||||||
set vg_cmd_file [test_valgrind_cmd_file $test]
|
if { $reason == "error" } {
|
||||||
set vg_stream [open $vg_cmd_file "w"]
|
set test_status "*ERROR*"
|
||||||
puts $vg_stream "cd [file dirname $cmd_file]"
|
} elseif { $reason == "no_cmd" } {
|
||||||
puts $vg_stream "include [file tail $cmd_file]"
|
set test_status "*NO CMD FILE*"
|
||||||
puts $vg_stream "sta::delete_all_memory"
|
} elseif { $reason == "memory" } {
|
||||||
close $vg_stream
|
set test_status "*MEMORY*"
|
||||||
|
} elseif { $reason == "leak" } {
|
||||||
set cmd [concat exec valgrind $valgrind_options \
|
set test_status "*LEAK*"
|
||||||
$app_path $app_options $vg_cmd_file >& $log_file]
|
} elseif { $reason == "fail" } {
|
||||||
set error_msg ""
|
set test_status "*FAIL*"
|
||||||
if { [catch $cmd] } {
|
} elseif { $reason == "no_ok" } {
|
||||||
set error_msg "ERROR [lindex $errorCode 3]"
|
set test_status "*NO OK FILE*"
|
||||||
|
} else {
|
||||||
|
error "unknown test failure reason $reason"
|
||||||
|
}
|
||||||
|
lappend failed_tests $test
|
||||||
|
incr errors($reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
proc write_failure_file {} {
|
||||||
|
global failure_file failed_tests
|
||||||
|
|
||||||
|
set ch [open $failure_file "w"]
|
||||||
|
foreach test $failed_tests {
|
||||||
|
puts $ch $test
|
||||||
|
}
|
||||||
|
close $ch
|
||||||
|
}
|
||||||
|
|
||||||
|
proc write_diff_file {} {
|
||||||
|
global diff_file diff_options failed_tests
|
||||||
|
|
||||||
|
foreach test $failed_tests {
|
||||||
|
set log_file [test_log_file $test]
|
||||||
|
set ok_file [test_ok_file $test]
|
||||||
|
catch [concat exec diff $diff_options $ok_file $log_file >> $diff_file]
|
||||||
}
|
}
|
||||||
file delete $vg_cmd_file
|
|
||||||
set error_msg [concat $error_msg [cleanse_valgrind_logfile $test $log_file]]
|
|
||||||
return $error_msg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Error messages can be found in "valgrind/memcheck/mc_errcontext.c".
|
# Error messages can be found in "valgrind/memcheck/mc_errcontext.c".
|
||||||
|
|
@ -363,25 +477,26 @@ set valgrind_shared_lib_failure_regexp "No malloc'd blocks -- no leaks are possi
|
||||||
|
|
||||||
# Scan the log file to separate valgrind notifications and check for
|
# Scan the log file to separate valgrind notifications and check for
|
||||||
# valgrind errors.
|
# valgrind errors.
|
||||||
proc cleanse_valgrind_logfile { test log_file } {
|
proc cleanse_valgrind_logfile { test } {
|
||||||
global valgrind_mem_regexp valgrind_leak_regexp
|
global valgrind_mem_regexp valgrind_leak_regexp
|
||||||
global valgrind_shared_lib_failure_regexp
|
global valgrind_shared_lib_failure_regexp
|
||||||
global valgrind_shared_lib_failure
|
global valgrind_shared_lib_failure error
|
||||||
|
|
||||||
|
set log_file [test_log_file $test]
|
||||||
set tmp_file [test_tmp_file $test]
|
set tmp_file [test_tmp_file $test]
|
||||||
set valgrind_log_file [test_valgrind_file $test]
|
set valgrind_log_file [test_valgrind_file $test]
|
||||||
file copy -force $log_file $tmp_file
|
file copy -force $log_file $tmp_file
|
||||||
set tmp [open $tmp_file "r"]
|
set tmp [open $tmp_file "r"]
|
||||||
set log [open $log_file "w"]
|
set log [open $log_file "w"]
|
||||||
set valgrind [open $valgrind_log_file "w"]
|
set valgrind [open $valgrind_log_file "w"]
|
||||||
set leaks 0
|
set leak 0
|
||||||
set mem_errors 0
|
set mem_errors 0
|
||||||
gets $tmp line
|
gets $tmp line
|
||||||
while { ![eof $tmp] } {
|
while { ![eof $tmp] } {
|
||||||
if {[regexp "^==" $line]} {
|
if {[regexp "^==" $line]} {
|
||||||
puts $valgrind $line
|
puts $valgrind $line
|
||||||
if {[regexp $valgrind_leak_regexp $line]} {
|
if {[regexp $valgrind_leak_regexp $line]} {
|
||||||
set leaks 1
|
set leak 1
|
||||||
}
|
}
|
||||||
if {[regexp $valgrind_mem_regexp $line]} {
|
if {[regexp $valgrind_mem_regexp $line]} {
|
||||||
set mem_errors 1
|
set mem_errors 1
|
||||||
|
|
@ -399,16 +514,12 @@ proc cleanse_valgrind_logfile { test log_file } {
|
||||||
close $log
|
close $log
|
||||||
close $tmp
|
close $tmp
|
||||||
close $valgrind
|
close $valgrind
|
||||||
file delete $tmp_file
|
|
||||||
|
|
||||||
set errors {}
|
|
||||||
if { $mem_errors } {
|
if { $mem_errors } {
|
||||||
lappend errors "MEMORY"
|
test_failed $test "memory"
|
||||||
|
} elseif { $leak } {
|
||||||
|
test_failed $test "leak"
|
||||||
}
|
}
|
||||||
if { $leaks } {
|
|
||||||
lappend errors "LEAK"
|
|
||||||
}
|
|
||||||
return $errors
|
|
||||||
}
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
@ -533,11 +644,6 @@ proc test_tmp_file { test } {
|
||||||
return [file join $result_dir $test.tmp]
|
return [file join $result_dir $test.tmp]
|
||||||
}
|
}
|
||||||
|
|
||||||
proc test_valgrind_cmd_file { test } {
|
|
||||||
global result_dir
|
|
||||||
return [file join $result_dir $test.vg_cmd]
|
|
||||||
}
|
|
||||||
|
|
||||||
proc test_valgrind_file { test } {
|
proc test_valgrind_file { test } {
|
||||||
global result_dir
|
global result_dir
|
||||||
return [file join $result_dir $test.valgrind]
|
return [file join $result_dir $test.valgrind]
|
||||||
|
|
@ -563,6 +669,11 @@ proc test_sys_core_file { test pid } {
|
||||||
return [file join [test_cmd_dir $test] "core"]
|
return [file join [test_cmd_dir $test] "core"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc test_exit_code_file { test } {
|
||||||
|
global result_dir
|
||||||
|
return [file join $result_dir "$test.exitcode"]
|
||||||
|
}
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue