17
17
require 'json'
18
18
require 'timeout'
19
19
require 'yaml'
20
- require 'open3'
21
20
require 'rbconfig'
22
21
require 'pathname'
23
22
53
52
54
53
require "#{ TRUFFLERUBY_DIR } /lib/truffle/truffle/openssl-prefix.rb"
55
54
56
- # wait for sub-processes to handle the interrupt
57
- trap ( :INT ) { }
58
-
59
55
MRI_TEST_MODULES = {
60
56
'--no-sulong' => {
61
57
help : 'exclude all tests requiring Sulong' ,
81
77
}
82
78
}
83
79
80
+ SUBPROCESSES = [ ]
81
+
82
+ # Forward signals to sub-processes, so they get notified when sending a signal to jt
83
+ [ :SIGINT , :SIGTERM ] . each do |signal |
84
+ trap ( signal ) do
85
+ SUBPROCESSES . each do |pid |
86
+ puts "\n Sending #{ signal } to process #{ pid } "
87
+ begin
88
+ Process . kill ( signal , pid )
89
+ rescue Errno ::ESRCH
90
+ # Already killed
91
+ end
92
+ end
93
+ # Keep running jt which will wait for the subprocesses termination
94
+ end
95
+ end
96
+
84
97
module Utilities
85
98
private
86
99
@@ -131,7 +144,7 @@ def find_graal_javacmd_and_options
131
144
options = [ '--no-bootclasspath' ]
132
145
elsif graal_home
133
146
graal_home = File . expand_path ( graal_home , TRUFFLERUBY_DIR )
134
- output , _ = mx ( '-v' , '-p' , graal_home , 'vm' , '-version' , : err => :out , capture : true )
147
+ output = mx ( '-v' , '-p' , graal_home , 'vm' , '-version' , capture : true , : err => :out )
135
148
command_line = output . lines . select { |line | line . include? '-version' }
136
149
if command_line . size == 1
137
150
command_line = command_line [ 0 ]
@@ -288,25 +301,34 @@ def diff(expected, actual)
288
301
`diff -u #{ expected } #{ actual } `
289
302
end
290
303
291
- def system_timeout ( timeout , *args )
292
- begin
293
- pid = Process . spawn ( *args )
294
- rescue SystemCallError
295
- return nil
296
- end
304
+ def raw_sh_failed_status
305
+ `false`
306
+ $?
307
+ end
297
308
298
- begin
299
- Timeout . timeout timeout do
300
- Process . waitpid pid
301
- $?. success?
309
+ def raw_sh_with_timeout ( timeout , pid )
310
+ if !timeout
311
+ yield
312
+ else
313
+ begin
314
+ Timeout . timeout ( timeout ) do
315
+ yield
316
+ end
317
+ rescue Timeout ::Error
318
+ Process . kill ( 'TERM' , pid )
319
+ yield # Wait and read the pipe if capture: true
320
+ :timeout
302
321
end
303
- rescue Timeout ::Error
304
- Process . kill ( 'TERM' , pid )
305
- Process . waitpid pid
306
- nil
307
322
end
308
323
end
309
324
325
+ def raw_sh_track_subprocess ( pid )
326
+ SUBPROCESSES << pid
327
+ yield
328
+ ensure
329
+ SUBPROCESSES . delete ( pid )
330
+ end
331
+
310
332
def raw_sh ( *args )
311
333
options = args . last . is_a? ( Hash ) ? args . last : { }
312
334
continue_on_failure = options . delete :continue_on_failure
@@ -318,44 +340,51 @@ def raw_sh(*args)
318
340
STDERR . puts "$ #{ printable_cmd ( args ) } "
319
341
end
320
342
321
- if use_exec
322
- result = exec ( *args )
323
- elsif timeout
324
- result = system_timeout ( timeout , *args )
325
- elsif capture
326
- if options . delete ( :out ) == :err
327
- err , status = Open3 . capture2e ( *args )
328
- out = ""
329
- else
330
- out , err , status = Open3 . capture3 ( *args )
331
- end
332
- result = status . success?
333
- else
334
- result = system ( *args )
343
+ exec ( *args ) if use_exec
344
+
345
+ if capture
346
+ raise ":capture can only be combined with :err => :out" if options . include? ( :out )
347
+ pipe_r , pipe_w = IO . pipe
348
+ options [ :out ] = pipe_w
349
+ options [ :err ] = pipe_w if options [ :err ] == :out
335
350
end
336
351
337
- if result
338
- if capture
339
- [ out , err ]
340
- else
341
- true
342
- end
343
- elsif continue_on_failure
344
- false
352
+ status = nil
353
+ out = nil
354
+ begin
355
+ pid = Process . spawn ( *args )
356
+ rescue Errno ::ENOENT # No such executable
357
+ status = raw_sh_failed_status
345
358
else
346
- status = $? unless capture
347
- $stderr . puts "FAILED ( #{ status } ): #{ printable_cmd ( args ) } "
359
+ raw_sh_track_subprocess ( pid ) do
360
+ pipe_w . close if capture
348
361
349
- if capture
350
- $stderr. puts out
351
- $stderr. puts err
362
+ result = raw_sh_with_timeout ( timeout , pid ) do
363
+ out = pipe_r . read if capture
364
+ _ , status = Process . waitpid2 ( pid )
365
+ end
366
+ if result == :timeout
367
+ status = raw_sh_failed_status
368
+ end
352
369
end
370
+ end
353
371
354
- if status && status . exitstatus
355
- exit status . exitstatus
372
+ result = status . success?
373
+
374
+ if capture
375
+ pipe_r . close
376
+ end
377
+
378
+ if status . success? || continue_on_failure
379
+ if capture
380
+ out
356
381
else
357
- exit 1
382
+ status . success?
358
383
end
384
+ else
385
+ $stderr. puts "FAILED (#{ status } ): #{ printable_cmd ( args ) } "
386
+ $stderr. puts out if capture
387
+ exit status . to_i
359
388
end
360
389
end
361
390
@@ -794,7 +823,7 @@ def pr_clean(*args)
794
823
puts "Open PRs: #{ open_prs } "
795
824
796
825
sh 'git' , 'fetch' , Remotes . bitbucket , '--prune' # ensure we have locally only existing remote branches
797
- branches , _ = sh 'git' , 'branch' , '--remote' , '--list' , capture : true
826
+ branches = sh 'git' , 'branch' , '--remote' , '--list' , capture : true
798
827
branches_to_delete = branches .
799
828
scan ( /^ *#{ Remotes . bitbucket } \/ (github\/ pr\/ (\d +))$/ ) .
800
829
reject { |_ , number | open_prs . include? Integer ( number ) }
@@ -814,7 +843,7 @@ def pr_clean(*args)
814
843
def pr_push ( *args )
815
844
# Fetch PRs on GitHub
816
845
fetch = "+refs/pull/*/head:refs/remotes/#{ Remotes . github } /pr/*"
817
- out , _err = sh 'git' , 'config' , '--get-all' , "remote.#{ Remotes . github } .fetch" , capture : true
846
+ out = sh 'git' , 'config' , '--get-all' , "remote.#{ Remotes . github } .fetch" , capture : true
818
847
sh 'git' , 'config' , '--add' , "remote.#{ Remotes . github } .fetch" , fetch unless out . include? fetch
819
848
sh 'git' , 'fetch' , Remotes . github
820
849
@@ -823,7 +852,7 @@ def pr_push(*args)
823
852
github_pr_branch = "#{ Remotes . github } /pr/#{ pr_number } "
824
853
else
825
854
github_pr_branch = begin
826
- out , _err = sh 'git' , 'branch' , '-r' , '--contains' , 'HEAD' , capture : true
855
+ out = sh 'git' , 'branch' , '-r' , '--contains' , 'HEAD' , capture : true
827
856
candidate = out . lines . find { |l | l . strip . start_with? "#{ Remotes . github } /pr/" }
828
857
candidate && candidate . strip . chomp
829
858
end
@@ -868,9 +897,9 @@ def github(dir = TRUFFLERUBY_DIR)
868
897
def remote_urls ( dir = TRUFFLERUBY_DIR )
869
898
@remote_urls ||= Hash . new
870
899
@remote_urls [ dir ] ||= begin
871
- out , _err = raw_sh 'git' , '-C' , dir , 'remote' , capture : true , no_print_cmd : true
900
+ out = raw_sh 'git' , '-C' , dir , 'remote' , capture : true , no_print_cmd : true
872
901
out . split . map do |remote |
873
- url , _err = raw_sh 'git' , '-C' , dir , 'config' , '--get' , "remote.#{ remote } .url" , capture : true , no_print_cmd : true
902
+ url = raw_sh 'git' , '-C' , dir , 'config' , '--get' , "remote.#{ remote } .url" , capture : true , no_print_cmd : true
874
903
[ remote , url . chomp ]
875
904
end
876
905
end
@@ -1112,7 +1141,7 @@ def test_cexts(*args)
1112
1141
1113
1142
sh 'clang' , '-c' , '-emit-llvm' , *openssl_cflags , 'test/truffle/cexts/xopenssl/main.c' , '-o' , 'test/truffle/cexts/xopenssl/main.bc'
1114
1143
mx 'build' , '--dependencies' , 'SULONG_LAUNCHER' # For mx lli
1115
- out , _ = mx ( 'lli' , "-Dpolyglot.llvm.libraries=#{ openssl_lib } " , 'test/truffle/cexts/xopenssl/main.bc' , capture : true )
1144
+ out = mx ( 'lli' , "-Dpolyglot.llvm.libraries=#{ openssl_lib } " , 'test/truffle/cexts/xopenssl/main.bc' , capture : true )
1116
1145
raise out . inspect unless out == "5d41402abc4b2a76b9719d911017c592\n "
1117
1146
1118
1147
when 'minimum' , 'method' , 'module' , 'globals' , 'backtraces' , 'xopenssl'
@@ -1458,7 +1487,6 @@ def build_stats_native_runtime_compilable_methods(*args)
1458
1487
end
1459
1488
1460
1489
def metrics ( command , *args )
1461
- trap ( :INT ) { puts ; exit }
1462
1490
args = args . dup
1463
1491
case command
1464
1492
when 'alloc'
@@ -1481,8 +1509,8 @@ def metrics_alloc(*args)
1481
1509
samples = [ ]
1482
1510
METRICS_REPS . times do
1483
1511
log '.' , "sampling\n "
1484
- out , err = run_ruby '-J-Dtruffleruby.metrics.memory_used_on_exit=true' , '-J-verbose:gc' , *args , capture : true , no_print_cmd : true
1485
- samples . push memory_allocated ( out + err )
1512
+ out = run_ruby '-J-Dtruffleruby.metrics.memory_used_on_exit=true' , '-J-verbose:gc' , *args , capture : true , :err => :out , no_print_cmd : true
1513
+ samples . push memory_allocated ( out )
1486
1514
end
1487
1515
log "\n " , nil
1488
1516
range = samples . max - samples . min
@@ -1568,12 +1596,12 @@ def metrics_maxrss(*args)
1568
1596
log '.' , "sampling\n "
1569
1597
1570
1598
max_rss_in_mb = if LINUX
1571
- out , err = raw_sh ( '/usr/bin/time' , '-v' , '--' , find_launcher ( true ) , *args , capture : true , no_print_cmd : true )
1572
- err =~ /Maximum resident set size \( kbytes\) : (?<max_rss_in_kb>\d +)/m
1599
+ out = raw_sh ( '/usr/bin/time' , '-v' , '--' , find_launcher ( true ) , *args , capture : true , :err => :out , no_print_cmd : true )
1600
+ out =~ /Maximum resident set size \( kbytes\) : (?<max_rss_in_kb>\d +)/m
1573
1601
Integer ( $~[ :max_rss_in_kb ] ) / 1024.0
1574
1602
elsif MAC
1575
- out , err = raw_sh ( '/usr/bin/time' , '-l' , '--' , find_launcher ( true ) , *args , capture : true , no_print_cmd : true )
1576
- err =~ /(?<max_rss_in_bytes>\d +)\s +maximum resident set size/m
1603
+ out = raw_sh ( '/usr/bin/time' , '-l' , '--' , find_launcher ( true ) , *args , capture : true , :err => :out , no_print_cmd : true )
1604
+ out =~ /(?<max_rss_in_bytes>\d +)\s +maximum resident set size/m
1577
1605
Integer ( $~[ :max_rss_in_bytes ] ) / 1024.0 / 1024.0
1578
1606
else
1579
1607
raise "Can't measure RSS on this platform."
@@ -1610,9 +1638,9 @@ def metrics_native_instructions(*args)
1610
1638
1611
1639
use_json = args . delete '--json'
1612
1640
1613
- out , err = raw_sh ( 'perf' , 'stat' , '-e' , 'instructions' , '--' , find_launcher ( true ) , *args , capture : true , no_print_cmd : true )
1641
+ out = raw_sh ( 'perf' , 'stat' , '-e' , 'instructions' , '--' , find_launcher ( true ) , *args , capture : true , :err => :out , no_print_cmd : true )
1614
1642
1615
- err =~ /(?<instruction_count>[\d ,]+)\s +instructions/m
1643
+ out =~ /(?<instruction_count>[\d ,]+)\s +instructions/m
1616
1644
instruction_count = $~[ :instruction_count ] . gsub ( ',' , '' )
1617
1645
1618
1646
log "\n " , nil
@@ -1639,9 +1667,9 @@ def metrics_time(*args)
1639
1667
samples = METRICS_REPS . times . map do
1640
1668
log '.' , "sampling\n "
1641
1669
start = Time . now
1642
- _ , err = run_ruby ( *args , capture : true , no_print_cmd : true , :out => :err )
1670
+ out = run_ruby ( *args , capture : true , no_print_cmd : true , :err => :out )
1643
1671
finish = Time . now
1644
- get_times ( err , ( finish - start ) * 1000.0 )
1672
+ get_times ( out , ( finish - start ) * 1000.0 )
1645
1673
end
1646
1674
log "\n " , nil
1647
1675
@@ -1780,22 +1808,19 @@ def profile(*args)
1780
1808
run_args = *DEFAULT_PROFILE_OPTIONS + args
1781
1809
1782
1810
begin
1783
- profile_data , err = run_ruby ( env , *run_args , capture : true )
1784
- $stderr. puts ( err ) unless err . empty?
1811
+ profile_data = run_ruby ( env , *run_args , capture : true )
1785
1812
1786
1813
profile_data_file = Tempfile . new %w[ truffleruby-profile .json ]
1787
1814
profile_data_file . write ( profile_data )
1788
1815
profile_data_file . close
1789
1816
1790
- flamegraph_data , err = raw_sh "#{ repo } /stackcollapse-graalvm.rb" , profile_data_file . path , capture : true
1791
- $stderr. puts ( err ) unless err . empty?
1817
+ flamegraph_data = raw_sh "#{ repo } /stackcollapse-graalvm.rb" , profile_data_file . path , capture : true
1792
1818
1793
1819
flamegraph_data_file = Tempfile . new 'truffleruby-flamegraph-data'
1794
1820
flamegraph_data_file . write ( flamegraph_data )
1795
1821
flamegraph_data_file . close
1796
1822
1797
- svg_data , err = raw_sh "#{ repo } /flamegraph.pl" , flamegraph_data_file . path , capture : true
1798
- $stderr. puts ( err ) unless err . empty?
1823
+ svg_data = raw_sh "#{ repo } /flamegraph.pl" , flamegraph_data_file . path , capture : true
1799
1824
1800
1825
Dir . mkdir ( PROFILES_DIR ) unless Dir . exist? ( PROFILES_DIR )
1801
1826
svg_filename = "#{ PROFILES_DIR } /flamegraph_#{ Time . now . strftime ( "%Y%m%d-%H%M%S" ) } .svg"
@@ -1954,7 +1979,7 @@ def check_filename_length
1954
1979
1955
1980
def check_parser
1956
1981
build ( 'parser' )
1957
- diff , _err = sh 'git' , 'diff' , 'src/main/java/org/truffleruby/parser/parser/RubyParser.java' , :err => :out , capture : true
1982
+ diff = sh 'git' , 'diff' , 'src/main/java/org/truffleruby/parser/parser/RubyParser.java' , capture : true
1958
1983
unless diff . empty?
1959
1984
STDERR . puts "DIFF:"
1960
1985
STDERR . puts diff
0 commit comments