Changeset 220431 in webkit
- Timestamp:
- Aug 8, 2017 5:18:08 PM (7 years ago)
- Location:
- trunk/Tools
- Files:
-
- 1 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r220425 r220431 1 2017-08-08 Stephan Szabo <stephan.szabo@sony.com> 2 3 Separate jsc stress test script writer from run-jsc-stress-tests 4 https://bugs.webkit.org/show_bug.cgi?id=175216 5 6 Reviewed by Mark Lam. 7 8 * Scripts/run-jsc-stress-tests: 9 * Scripts/webkitruby/jsc-stress-test-writer-default.rb: Added. 10 1 11 2017-08-08 Michael Catanzaro <mcatanzaro@igalia.com> 2 12 -
trunk/Tools/Scripts/run-jsc-stress-tests
r220118 r220431 435 435 FTL_OPTIONS = ["--useFTLJIT=true"] 436 436 437 require_relative "webkitruby/jsc-stress-test-writer-default" 438 437 439 def shouldCollectContinuously? 438 440 $buildType == "release" or $forceCollectContinuously … … 472 474 end 473 475 474 def prefixCommand(prefix)475 "awk " + Shellwords.shellescape("{ printf #{(prefix + ': ').inspect}; print }")476 end477 478 def redirectAndPrefixCommand(prefix)479 prefixCommand(prefix) + " 2>&1"480 end481 482 def pipeAndPrefixCommand(outputFilename, prefix)483 "tee " + Shellwords.shellescape(outputFilename.to_s) + " | " + prefixCommand(prefix)484 end485 486 # Output handler for tests that are expected to be silent.487 def silentOutputHandler488 Proc.new {489 | name |490 " | " + pipeAndPrefixCommand((Pathname("..") + (name + ".out")).to_s, name)491 }492 end493 494 # Output handler for tests that are expected to produce meaningful output.495 def noisyOutputHandler496 Proc.new {497 | name |498 " | cat > " + Shellwords.shellescape((Pathname("..") + (name + ".out")).to_s)499 }500 end501 502 # Error handler for tests that fail exactly when they return non-zero exit status.503 # This is useful when a test is expected to fail.504 def simpleErrorHandler505 Proc.new {506 | outp, plan |507 outp.puts "if test -e #{plan.failFile}"508 outp.puts "then"509 outp.puts " (echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + redirectAndPrefixCommand(plan.name)510 outp.puts " " + plan.failCommand511 outp.puts "else"512 outp.puts " " + plan.successCommand513 outp.puts "fi"514 }515 end516 517 # Error handler for tests that fail exactly when they return zero exit status.518 def expectedFailErrorHandler519 Proc.new {520 | outp, plan |521 outp.puts "if test -e #{plan.failFile}"522 outp.puts "then"523 outp.puts " " + plan.successCommand524 outp.puts "else"525 outp.puts " (echo ERROR: Unexpected exit code: 0) | " + redirectAndPrefixCommand(plan.name)526 outp.puts " " + plan.failCommand527 outp.puts "fi"528 }529 end530 531 # Error handler for tests that fail exactly when they return non-zero exit status and produce532 # lots of spew. This will echo that spew when the test fails.533 def noisyErrorHandler534 Proc.new {535 | outp, plan |536 outputFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".out")).to_s)537 538 outp.puts "if test -e #{plan.failFile}"539 outp.puts "then"540 outp.puts " (cat #{outputFilename} && echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + redirectAndPrefixCommand(plan.name)541 outp.puts " " + plan.failCommand542 outp.puts "else"543 outp.puts " " + plan.successCommand544 outp.puts "fi"545 }546 end547 548 # Error handler for tests that diff their output with some expectation.549 def diffErrorHandler(expectedFilename)550 Proc.new {551 | outp, plan |552 outputFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".out")).to_s)553 diffFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".diff")).to_s)554 555 outp.puts "if test -e #{plan.failFile}"556 outp.puts "then"557 outp.puts " (cat #{outputFilename} && echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + redirectAndPrefixCommand(plan.name)558 outp.puts " " + plan.failCommand559 outp.puts "elif test -e ../#{Shellwords.shellescape(expectedFilename)}"560 outp.puts "then"561 outp.puts " diff --strip-trailing-cr -u ../#{Shellwords.shellescape(expectedFilename)} #{outputFilename} > #{diffFilename}"562 outp.puts " if [ $? -eq 0 ]"563 outp.puts " then"564 outp.puts " " + plan.successCommand565 outp.puts " else"566 outp.puts " (echo \"DIFF FAILURE!\" && cat #{diffFilename}) | " + redirectAndPrefixCommand(plan.name)567 outp.puts " " + plan.failCommand568 outp.puts " fi"569 outp.puts "else"570 outp.puts " (echo \"NO EXPECTATION!\" && cat #{outputFilename}) | " + redirectAndPrefixCommand(plan.name)571 outp.puts " " + plan.failCommand572 outp.puts "fi"573 }574 end575 576 # Error handler for tests that report error by saying "failed!". This is used by Mozilla577 # tests.578 def mozillaErrorHandler579 Proc.new {580 | outp, plan |581 outputFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".out")).to_s)582 583 outp.puts "if test -e #{plan.failFile}"584 outp.puts "then"585 outp.puts " (cat #{outputFilename} && echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + redirectAndPrefixCommand(plan.name)586 outp.puts " " + plan.failCommand587 outp.puts "elif grep -i -q failed! #{outputFilename}"588 outp.puts "then"589 outp.puts " (echo Detected failures: && cat #{outputFilename}) | " + redirectAndPrefixCommand(plan.name)590 outp.puts " " + plan.failCommand591 outp.puts "else"592 outp.puts " " + plan.successCommand593 outp.puts "fi"594 }595 end596 597 # Error handler for tests that report error by saying "failed!", and are expected to598 # fail. This is used by Mozilla tests.599 def mozillaFailErrorHandler600 Proc.new {601 | outp, plan |602 outputFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".out")).to_s)603 604 outp.puts "if test -e #{plan.failFile}"605 outp.puts "then"606 outp.puts " " + plan.successCommand607 outp.puts "elif grep -i -q failed! #{outputFilename}"608 outp.puts "then"609 outp.puts " " + plan.successCommand610 outp.puts "else"611 outp.puts " (echo NOTICE: You made this test pass, but it was expected to fail) | " + redirectAndPrefixCommand(plan.name)612 outp.puts " " + plan.failCommand613 outp.puts "fi"614 }615 end616 617 # Error handler for tests that report error by saying "failed!", and are expected to have618 # an exit code of 3.619 def mozillaExit3ErrorHandler620 Proc.new {621 | outp, plan |622 outputFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".out")).to_s)623 624 outp.puts "if test -e #{plan.failFile}"625 outp.puts "then"626 outp.puts " if [ `cat #{plan.failFile}` -eq 3 ]"627 outp.puts " then"628 outp.puts " if grep -i -q failed! #{outputFilename}"629 outp.puts " then"630 outp.puts " (echo Detected failures: && cat #{outputFilename}) | " + redirectAndPrefixCommand(plan.name)631 outp.puts " " + plan.failCommand632 outp.puts " else"633 outp.puts " " + plan.successCommand634 outp.puts " fi"635 outp.puts " else"636 outp.puts " (cat #{outputFilename} && echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + redirectAndPrefixCommand(plan.name)637 outp.puts " " + plan.failCommand638 outp.puts " fi"639 outp.puts "else"640 outp.puts " (cat #{outputFilename} && echo ERROR: Test expected to fail, but returned successfully) | " + redirectAndPrefixCommand(plan.name)641 outp.puts " " + plan.failCommand642 outp.puts "fi"643 }644 end645 646 # Error handler for tests that report success by saying "Passed" or error by saying "FAILED".647 # This is used by Chakra tests.648 def chakraPassFailErrorHandler649 Proc.new {650 | outp, plan |651 outputFilename = Shellwords.shellescape((Pathname("..") + (plan.name + ".out")).to_s)652 653 outp.puts "if test -e #{plan.failFile}"654 outp.puts "then"655 outp.puts " (cat #{outputFilename} && echo ERROR: Unexpected exit code: `cat #{plan.failFile}`) | " + redirectAndPrefixCommand(plan.name)656 outp.puts " " + plan.failCommand657 outp.puts "elif grep -i -q FAILED #{outputFilename}"658 outp.puts "then"659 outp.puts " (echo Detected failures: && cat #{outputFilename}) | " + redirectAndPrefixCommand(plan.name)660 outp.puts " " + plan.failCommand661 outp.puts "else"662 outp.puts " " + plan.successCommand663 outp.puts "fi"664 }665 end666 667 476 $runCommandOptions = {} 668 669 class Plan670 attr_reader :directory, :arguments, :family, :name, :outputHandler, :errorHandler671 attr_accessor :index672 673 def initialize(directory, arguments, family, name, outputHandler, errorHandler)674 @directory = directory675 @arguments = arguments676 @family = family677 @name = name678 @outputHandler = outputHandler679 @errorHandler = errorHandler680 @isSlow = !!$runCommandOptions[:isSlow]681 end682 683 def shellCommand684 # It's important to remember that the test is actually run in a subshell, so if we change directory685 # in the subshell when we return we will be in our original directory. This is nice because we don't686 # have to bend over backwards to do things relative to the root.687 script = "(cd ../#{Shellwords.shellescape(@directory.to_s)} && ("688 $envVars.each { |var| script += "export " << var << "; " }689 script += "\"$@\" " + escapeAll(@arguments) + "))"690 return script691 end692 693 def reproScriptCommand694 # We have to find our way back to the .runner directory since that's where all of the relative695 # paths assume they start out from.696 script = "CURRENT_DIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" && pwd )\"\n"697 script += "cd $CURRENT_DIR\n"698 Pathname.new(@name).dirname.each_filename {699 | pathComponent |700 script += "cd ..\n"701 }702 script += "cd .runner\n"703 704 script += "export DYLD_FRAMEWORK_PATH=$(cd #{$testingFrameworkPath.dirname}; pwd)\n"705 script += "export JSCTEST_timeout=#{Shellwords.shellescape(ENV['JSCTEST_timeout'])}\n"706 $envVars.each { |var| script += "export " << var << "\n" }707 script += "#{shellCommand} || exit 1"708 "echo #{Shellwords.shellescape(script)} > #{Shellwords.shellescape((Pathname.new("..") + @name).to_s)}"709 end710 711 def failCommand712 "echo FAIL: #{Shellwords.shellescape(@name)} ; touch #{failFile} ; " + reproScriptCommand713 end714 715 def successCommand716 if $progressMeter or $verbosity >= 2717 "rm -f #{failFile} ; echo PASS: #{Shellwords.shellescape(@name)}"718 else719 "rm -f #{failFile}"720 end721 end722 723 def failFile724 "test_fail_#{@index}"725 end726 727 def writeRunScript(filename)728 File.open(filename, "w") {729 | outp |730 outp.puts "echo Running #{Shellwords.shellescape(@name)}"731 cmd = "(" + shellCommand + " || (echo $? > #{failFile})) 2>&1 "732 cmd += @outputHandler.call(@name)733 if $verbosity >= 3734 outp.puts "echo #{Shellwords.shellescape(cmd)}"735 end736 outp.puts cmd737 @errorHandler.call(outp, self)738 }739 end740 end741 477 742 478 $uniqueFilenameCounter = 0 … … 1896 1632 end 1897 1633 1898 def prepareShellTestRunner1899 FileUtils.cp SCRIPTS_PATH + "jsc-stress-test-helpers" + "shell-runner.sh", $runnerDir + "runscript"1900 end1901 1902 def prepareMakeTestRunner1903 # The goals of our parallel test runner are scalability and simplicity. The1904 # simplicity part is particularly important. We don't want to have to have1905 # a full-time contributor just philosophising about parallel testing.1906 #1907 # As such, we just pass off all of the hard work to 'make'. This creates a1908 # dummy directory ("$outputDir/.runner") in which we create a dummy1909 # Makefile. The Makefile has an 'all' rule that depends on all of the tests.1910 # That is, for each test we know we will run, there is a rule in the1911 # Makefile and 'all' depends on it. Running 'make -j <whatever>' on this1912 # Makefile results in 'make' doing all of the hard work:1913 #1914 # - Load balancing just works. Most systems have a great load balancer in1915 # 'make'. If your system doesn't then just install a real 'make'.1916 #1917 # - Interruptions just work. For example Ctrl-C handling in 'make' is1918 # exactly right. You don't have to worry about zombie processes.1919 #1920 # We then do some tricks to make failure detection work and to make this1921 # totally sound. If a test fails, we don't want the whole 'make' job to1922 # stop. We also don't have any facility for makefile-escaping of path names.1923 # We do have such a thing for shell-escaping, though. We fix both problems1924 # by having the actual work for each of the test rules be done in a shell1925 # script on the side. There is one such script per test. The script responds1926 # to failure by printing something on the console and then touching a1927 # failure file for that test, but then still returns 0. This makes 'make'1928 # continue past that failure and complete all the tests anyway.1929 #1930 # In the end, this script collects all of the failures by searching for1931 # files in the .runner directory whose name matches /^test_fail_/, where1932 # the thing after the 'fail_' is the test index. Those are the files that1933 # would be created by the test scripts if they detect failure. We're1934 # basically using the filesystem as a concurrent database of test failures.1935 # Even if two tests fail at the same time, since they're touching different1936 # files we won't miss any failures.1937 runIndices = []1938 $runlist.each {1939 | plan |1940 runIndices << plan.index1941 }1942 1943 File.open($runnerDir + "Makefile", "w") {1944 | outp |1945 outp.puts("all: " + runIndices.map{|v| "test_done_#{v}"}.join(' '))1946 runIndices.each {1947 | index |1948 plan = $runlist[index]1949 outp.puts "test_done_#{index}:"1950 outp.puts "\tsh test_script_#{plan.index}"1951 }1952 }1953 end1954 1955 1634 def cleanRunnerDirectory 1956 1635 raise unless $bundle … … 2078 1757 2079 1758 def runTestRunner 2080 case $testRunnerType2081 when :shell2082 testRunnerCommand = "sh runscript"2083 when :make2084 testRunnerCommand = "make -j #{$numChildProcesses.to_s} -s -f Makefile"2085 else2086 raise "Unknown test runner type: #{$testRunnerType.to_s}"2087 end2088 2089 1759 if $remote 2090 1760 if !$remoteDirectory
Note: See TracChangeset
for help on using the changeset viewer.