blob: 7f449e0f4518d9cc00e3d35bd09eb219f284c742 [file] [log] [blame]
#!/usr/bin/tclsh
# Copyright 2019 Alain Dargelas
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
proc printHelp {} {
puts "regression.tcl help"
puts "regression.tcl tests=<testname> (Tests matching regular expression)"
puts " test=<testname> (Just that test)"
puts " debug=<none, valgrind, ddd>"
puts " build=<debug, advanced, release, notcmalloc, undertow>"
puts " commit=\"commit text\""
puts " mt=<nbThreads>"
puts " large (large tests too)"
puts " show_diff (Shows text diff)"
puts "regression.tcl update (Updates the diffs)"
}
proc log { text } {
global LOG_FILE
puts $text
flush stdout
if ![info exist LOG_FILE] {
set LOG_FILE [open regression.log "w"]
}
puts $LOG_FILE $text
flush $LOG_FILE
}
proc log_nonewline { text } {
global LOG_FILE
puts -nonewline $text
flush stdout
if ![info exist LOG_FILE] {
set LOG_FILE [open regression.log "w"]
}
puts -nonewline $LOG_FILE $text
flush $LOG_FILE
}
set UPDATE 0
set TIME "/usr/bin/time"
set DEBUG_TOOL ""
set PRIOR_USER 0
set PRIOR_ELAPSED 0
set USER 0
set ELAPSED 0
set PRIOR_MAX_MEM 0
set MAX_MEM 0
set PRIOR_MAX_TIME 0
set MAX_TIME 0
set DEBUG "none"
set MT_MAX ""
set LARGE_TESTS 0
set SHOW_DIFF 0
set LONG_TESTS(YosysOpenSparc) 1
set LONG_TESTS(YosysOldTests) 1
set LONG_TESTS(YosysRiscv) 1
set LONG_TESTS(YosysBigSim) 1
set LONG_TESTS(YosysBoom) 1
set LONG_TESTS(YosysEth) 1
set LONG_TESTS(YosysIce40) 1
set LONG_TESTS(YosysBigSimEllip) 1
set LONG_TESTS(YosysTests) 1
set LONG_TESTS(YosysBigSimBch) 1
# Noisy test
set LONG_TESTS(YosysTestSuite) 1
set LONG_TESTS(SimpleParserTestCache) 1
if [regexp {show_diff} $argv] {
regsub "show_diff" $argv "" argv
set SHOW_DIFF 1
}
if [regexp {large} $argv] {
set LARGE_TESTS 1
log "Running large tests"
} else {
log "Skipping large tests"
}
if [regexp {mt=([0-9]+)} $argv tmp MT_MAX] {
log "Run with -mt $MT_MAX"
}
if [regexp {debug=([a-z]+)} $argv tmp DEBUG] {
if {$DEBUG == "valgrind"} {
set DEBUG_TOOL "valgrind --tool=memcheck --log-file=valgrind.log"
}
if {$DEBUG == "ddd"} {
set DEBUG_TOOL "ddd"
}
}
if {$argv == "help"} {
printHelp
exit
}
set TESTTARGET ""
set ONETEST ""
if [regexp {tests=([A-Za-z0-9_]+)} $argv tmp TESTTARGET] {
}
if [regexp {test=([A-Za-z0-9_]+)} $argv tmp TESTTARGET] {
set ONETEST $TESTTARGET
}
set BUILD "release"
if [regexp {build=([A-Za-z0-9_]+)} $argv tmp BUILD] {
}
set SHOW_DETAILS 0
if [regexp {\-details} $argv] {
set SHOW_DETAILS 1
}
if [regexp {update} $argv] {
set UPDATE 1
}
log $argv
set COMMIT_TEXT ""
if [regexp {commit=([A-Za-z0-9_ \.]+)} $argv tmp COMMIT_TEXT] {
}
set SURELOG_VERSION "[pwd]/../dist/surelog/surelog"
set REGRESSION_PATH [pwd]
set SURELOG_COMMAND "$TIME $DEBUG_TOOL $SURELOG_VERSION"
proc init_regression { } {
global BUILD
log "Creating release for regression..."
cd ..
log [exec sh -c "./release.tcl \"$BUILD tcmalloc\""]
cd Testcases
}
proc load_tests { } {
global TESTS TESTS_DIR LONGESTTESTNAME TESTTARGET ONETEST LARGE_TESTS LONG_TESTS
set fid [open "../nbproject/launcher.properties"]
set content [read $fid]
close $fid
set lines [split $content "\n"]
set testcommand ""
set LONGESTTESTNAME 1
set totaltest 0
foreach line $lines {
if [regexp {launcher[0-9]+\.displayName=([a-zA-Z_0-9]+)} $line tmp testname] {
set testcommand ""
} elseif [regexp {launcher[0-9]+\.runCommand=\"\${PROJECT_DIR}/\${OUTPUT_PATH}\" (.*)} $line tmp testcommand] {
} elseif [regexp {launcher[0-9]+\.runCommand=(.*) \"\${PROJECT_DIR}/\${OUTPUT_PATH}\"} $line tmp testcommand] {
} elseif [regexp {launcher[0-9]+\.runDir=([a-zA-Z_0-9/-]+)} $line tmp testdir] {
incr totaltest
if {($TESTTARGET != "") && ![regexp $TESTTARGET $testname]} {
continue
}
if {($ONETEST != "") && ($ONETEST != $testname)} {
continue
}
if {($ONETEST == "") && ($LARGE_TESTS == 0)} {
if [info exist LONG_TESTS($testname)] {
continue
}
}
if {$LONGESTTESTNAME < [string length $testname]} {
set LONGESTTESTNAME [string length $testname]
}
set TESTS($testname) $testcommand
set TESTS_DIR($testname) $testdir
} else {
set testcommand "$testcommand $line"
}
}
log "THERE ARE $totaltest tests"
log "RUNNING [array size TESTS] tests"
log ""
}
proc count_messages { result } {
set fatals -1
set errors -1
set warnings -1
set notes -1
set syntax 0
# Normal test
regexp {FATAL\] : ([0-9]+)} $result tmp fatals
regexp {ERROR\] : ([0-9]+)} $result tmp errors
regexp {WARNING\] : ([0-9]+)} $result tmp warnings
regexp {NOTE\] : ([0-9]+)} $result tmp notes
# Diff test
if [regexp {\| FATAL \|[ ]*([0-9]+)[ ]*\|[ ]*([0-9]+)[ ]*} $result tmp fatal1 fatal2] {
set fatals [expr $fatal1 + $fatal2]
}
if [regexp {\| ERROR \|[ ]*([0-9]+)[ ]*\|[ ]*([0-9]+)[ ]*} $result tmp error1 error2] {
set errors [expr $error1 + $error2]
}
if [regexp {\|WARNING\|[ ]*([0-9]+)[ ]*\|[ ]*([0-9]+)[ ]*} $result tmp warning1 warning2] {
set warnings [expr $warning1 + $warning2]
}
if [regexp {\| NOTE \|[ ]*([0-9]+)[ ]*\|[ ]*([0-9]+)[ ]*} $result tmp note1 note2] {
set notes [expr $note1 + $note2]
}
# Show help test
if [regexp {outputlineinfo} $result] {
set fatals 0
set errors 0
set warnings 0
set notes 0
}
# stats per message ID
set lines [split $result "\n"]
foreach line $lines {
if [regexp {Syntax error} $line] {
incr syntax
}
if [regexp {(\[.*\])} $line tmp code] {
if [info exist CODES($code)] {
incr CODES($code)
} else {
set CODES($code) 1
}
}
}
set details ""
foreach name [lsort -dictionary [array names CODES]] {
lappend details [list $name $CODES($name)]
}
return [list $fatals $errors $warnings $notes $details $syntax]
}
proc run_regression { } {
global TESTS TESTS_DIR SURELOG_COMMAND LONGESTTESTNAME TESTTARGET ONETEST UPDATE USER ELAPSED PRIOR_USER PRIOR_ELAPSED
global DIFF_TESTS PRIOR_MAX_MEM MAX_MEM MAX_TIME PRIOR_MAX_TIME SHOW_DETAILS MT_MAX REGRESSION_PATH LARGE_TESTS LONG_TESTS
set overrallpass "PASS"
set w1 $LONGESTTESTNAME
set w2 8
set w4 8
set w3 18
set w5 12
set MEM 0
set sep +-[string repeat - $w1]-+-[string repeat - $w2]-+-[string repeat - $w2]-+-[string repeat - $w4]-+-[string repeat - $w2]-+-[string repeat - $w4]-+-[string repeat - $w2]-+-[string repeat - $w5]-+-[string repeat - $w5]-+
log $sep
log [format "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |" $w1 "TESTNAME" $w2 "STATUS" $w2 "FATALS" $w4 "ERRORS" $w2 "WARNINGS" $w4 "NOTES" $w2 "SYNTAX" $w5 "ELAPSED TIME" $w5 "MEM(Mb)"]
log $sep
foreach testname [array names TESTS] {
if {($ONETEST != "") && ($testname != $ONETEST)} {
continue
}
if {($ONETEST == "") && ($LARGE_TESTS == 0)} {
if [info exist LONG_TESTS($testname)] {
continue
}
}
set testdir $TESTS_DIR($testname)
regsub "Testcases/" $testdir "" test
set command $TESTS($testname)
regsub -all {\\} $command "" command
if {($ONETEST != "")} {
log "\ncd $test"
if [regexp {\.sh} $command] {
log "$command [lindex $SURELOG_COMMAND 1]\n"
} else {
log "$SURELOG_COMMAND $command\n"
}
}
if {$UPDATE == 1} {
if [file exist "$test/${testname}_diff.log"] {
log [format "| %-*s | Copying $test/${testname}_diff.log to $test/${testname}.log" $w1 $testname]
file copy -force "$test/${testname}_diff.log" "$test/${testname}.log"
continue
} else {
log [format "| %-*s | No action" $w1 $testname]
continue
}
}
log_nonewline [format "| %-*s |" $w1 $testname]
cd $test
exec sh -c "rm -rf slpp*"
set passstatus "PASS"
if {($ONETEST != "") && [regexp {ddd} $SURELOG_COMMAND]} {
log "\nrun $command\n"
catch {set result [exec sh -c "$SURELOG_COMMAND"]} result
exit
}
if [regexp {\.sh} $command] {
catch {set result [exec sh -c "time $command [lindex $SURELOG_COMMAND 1]"]} result
} else {
if {$MT_MAX != ""} {
set command "$command -mt $MT_MAX"
}
catch {set result [exec sh -c "$SURELOG_COMMAND $command"]} result
}
set segfault 0
if [regexp {Segmentation fault} $result] {
set segfault 1
exec sh -c "rm -rf slpp*"
if [regexp {\.sh} $command] {
catch {set result [exec sh -c "time $command [lindex $SURELOG_COMMAND 1]"]} result
} else {
catch {set result [exec sh -c "$SURELOG_COMMAND $command"]} result
}
if [regexp {Segmentation fault} $result] {
set passstatus "FAIL"
set overrallpass "FAIL"
set segfault 2
} else {
set segfault 0
}
}
if [regexp {AdvancedDebug} $SURELOG_COMMAND] {
log $result
}
set fatals -1
set errors -1
set warnings -1
set notes -1
set log_fatals -1
set log_errors -1
set log_warnings -1
set log_notes -1
set user 0
set elapsed_min 0
set elapsed 0
set cpu 0
foreach {fatals errors warnings notes details syntax} [count_messages $result] {}
if [regexp {([0-9\.:]+)user [0-9\.:]+system ([0-9]+):([0-9\.]+)elapsed ([0-9]+)%CPU} $result tmp user elapsed_min elapsed cpu] {
set user [expr int($user)]
set elapsed [expr int(($elapsed_min *60) + $elapsed)]
set USER [expr $USER + $user]
set ELAPSED [expr $ELAPSED + $elapsed]
if {$MAX_TIME < $elapsed} {
set MAX_TIME $elapsed
}
}
set mem 0
if [regexp {([0-9]+)maxresident} $result tmp mem] {
set mem [expr $mem / 1024]
if {$MAX_MEM < $mem} {
set MAX_MEM $mem
}
}
set SPEED ""
set FASTER_OR_SLOWER 0
set DIFF_MEM 0
if [file exists "$testname.log"] {
set fid [open "$testname.log" "r"]
set content [read $fid]
close $fid
foreach {log_fatals log_errors log_warnings log_notes log_details log_syntax} [count_messages $content] {}
set prior_user 0
set prior_elapsed_min 0
set prior_elapsed 0
set cpu 0
if [regexp {([0-9\.]+)user [0-9\.:]+system ([0-9]+):([0-9\.]+)elapsed ([0-9]+)%CPU} $content tmp prior_user prior_elapsed_min prior_elapsed cpu] {
set prior_user [expr int($prior_user)]
set prior_elapsed [expr int(($prior_elapsed_min *60) + $prior_elapsed)]
set PRIOR_USER [expr $PRIOR_USER + $prior_user]
set PRIOR_ELAPSED [expr $PRIOR_ELAPSED + $prior_elapsed]
if {$PRIOR_MAX_TIME < $prior_elapsed} {
set PRIOR_MAX_TIME $prior_elapsed
}
if [expr $elapsed > $prior_elapsed] {
set SPEED [format "%-*s %-*s " 4 "${elapsed}s" 5 "(+[expr $elapsed - $prior_elapsed]s)"]
set FASTER_OR_SLOWER 1
} elseif [expr $elapsed == $prior_elapsed] {
set SPEED [format "%-*s " 4 "${elapsed}s"]
} else {
set SPEED [format "%-*s %-*s " 4 "${elapsed}s" 5 "(-[expr $prior_elapsed - $elapsed]s)"]
set FASTER_OR_SLOWER 1
}
}
set prior_mem 0
if [regexp {([0-9]+)maxresident} $content tmp prior_mem] {
set prior_mem [expr $prior_mem / 1024]
if {$PRIOR_MAX_MEM < $prior_mem} {
set PRIOR_MAX_MEM $prior_mem
}
if [expr $mem > $prior_mem] {
set MEM [format "%-*s %-*s " 4 "${mem}" 5 "(+[expr $mem - $prior_mem])"]
set DIFF_MEM 1
} elseif [expr $mem == $prior_mem] {
set MEM [format "%-*s " 4 "${mem}"]
} else {
set MEM [format "%-*s %-*s " 4 "${mem}" 5 "(-[expr $prior_mem - $mem])"]
set DIFF_MEM 1
}
}
if {($fatals != $log_fatals) || ($errors != $log_errors) || ($warnings != $log_warnings) || ($notes != $log_notes) || ($syntax != $log_syntax)} {
set overrallpass "DIFF"
set passstatus "DIFF"
set DIFF_TESTS($testname) $test
if {$fatals != $log_fatals} {
set fatals "$fatals ([expr $fatals - $log_fatals])"
}
if {$errors != $log_errors} {
set errors "$errors ([expr $errors - $log_errors])"
}
if {$warnings != $log_warnings} {
set warnings "$warnings ([expr $warnings - $log_warnings])"
}
if {$notes != $log_notes} {
set notes "$notes ([expr $notes - $log_notes])"
}
if {$syntax != $log_syntax} {
set syntax "$syntax ([expr $syntax - $log_syntax])"
}
}
}
if {($fatals == -1) || ($errors == -1) || ($warnings == -1) || ($notes == -1)} {
if {$segfault == 0} {
set segfault 1
}
set fatals "segfault"
set passstatus "FAIL"
set overrallpass "FAIL"
}
if {$segfault == 1 || $segfault == 2} {
set fatals "segfault"
}
log [format " %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |" $w2 $passstatus $w2 $fatals $w4 $errors $w2 $warnings $w4 $notes $w2 $syntax $w5 $SPEED $w5 $MEM ]
flush stdout
if {$SHOW_DETAILS == 1} {
log "Log:\n"
foreach de $details {
log $de
}
log "Diff Log:\n"
foreach de $log_details {
log $de
}
}
set fid 0
if {(($passstatus == "PASS") && ($DIFF_MEM == 0) && ($FASTER_OR_SLOWER == 0)) || ($UPDATE == 1)} {
set fid [open "$testname.log" "w"]
} else {
set fid [open "${testname}_diff.log" "w"]
}
puts $fid $result
close $fid
cd $REGRESSION_PATH
}
log $sep
return $overrallpass
}
log "************************"
log "START SURELOG REGRESSION"
log ""
set systemTime [clock seconds]
set date "Starts on [clock format $systemTime -format %D] [clock format $systemTime -format %H:%M:%S]"
log "$date"
log "COMMAND: $SURELOG_COMMAND"
init_regression
load_tests
set result [run_regression]
log "\n RESULT : $result\n"
if {$COMMIT_TEXT != ""} {
if {($result == "PASS") && ($ONETEST == "") && ($TESTTARGET =="")} {
log "git commit -m \"$COMMIT_TEXT\""
exec sh -c "cd ~/surelog; git commit . -m \"$COMMIT_TEXT\""
exec sh -c "git push"
} else {
log "CANNOT COMMIT CHANGES: $COMMIT_TEXT"
}
log ""
}
foreach testname [array names DIFF_TESTS] {
if {$SHOW_DIFF == 0} {
log " tkdiff $DIFF_TESTS($testname)/${testname}.log $DIFF_TESTS($testname)/${testname}_diff.log"
} else {
log "============================== DIFF ======================================================"
log "diff $DIFF_TESTS($testname)/${testname}.log $DIFF_TESTS($testname)/${testname}_diff.log"
catch {exec sh -c "diff -d $DIFF_TESTS($testname)/${testname}.log $DIFF_TESTS($testname)/${testname}_diff.log"} dummy
puts $dummy
}
}
if [info exists DIFF_TESTS] {
log ""
}
set w1 8
set sep +-[string repeat - 12]-+-[string repeat - $w1]-+-[string repeat - $w1]-+
log $sep
log [format "| | %-*s | %-*s |" $w1 "CURRENT" $w1 "PREVIOUS" ]
log $sep
log [format "|TOTAL ELAPSED | %-*s | %-*s |" $w1 "${ELAPSED}s" $w1 "${PRIOR_ELAPSED}s" ]
log [format "|TOTAL USER | %-*s | %-*s |" $w1 "${USER}s" $w1 "${PRIOR_USER}s"]
log [format "|MAX MEM TEST | %-*s | %-*s |" $w1 "${MAX_MEM}Mb" $w1 "${PRIOR_MAX_MEM}Mb"]
log [format "|MAX TIME TEST | %-*s | %-*s |" $w1 "${MAX_TIME}s" $w1 "${PRIOR_MAX_TIME}s"]
log $sep
log ""
set systemTime [clock seconds]
set date "End on [clock format $systemTime -format %D] [clock format $systemTime -format %H:%M:%S]"
log "$date"
log "END SURELOG REGRESSION"
log "************************"
if {$result == "PASS"} {
exit 0
} else {
exit 1
}