t2-server 0.9.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.rdoc +79 -0
- data/LICENCE.rdoc +1 -1
- data/README.rdoc +94 -26
- data/Rakefile +6 -5
- data/bin/t2-delete-runs +25 -23
- data/bin/t2-get-output +11 -13
- data/bin/t2-run-workflow +91 -29
- data/bin/t2-server-info +29 -12
- data/extras/t2-server-stress +184 -0
- data/lib/t2-server-cli.rb +48 -23
- data/lib/t2-server.rb +2 -1
- data/lib/t2-server/admin.rb +7 -4
- data/lib/t2-server/exceptions.rb +23 -4
- data/lib/t2-server/interaction.rb +241 -0
- data/lib/t2-server/net/connection.rb +90 -60
- data/lib/t2-server/net/credentials.rb +25 -9
- data/lib/t2-server/net/parameters.rb +21 -6
- data/lib/t2-server/port.rb +229 -140
- data/lib/t2-server/run-cache.rb +99 -0
- data/lib/t2-server/run.rb +349 -332
- data/lib/t2-server/server.rb +115 -164
- data/lib/t2-server/util.rb +11 -9
- data/lib/t2-server/xml/libxml.rb +3 -2
- data/lib/t2-server/xml/nokogiri.rb +4 -3
- data/lib/t2-server/xml/rexml.rb +3 -2
- data/lib/t2-server/xml/xml.rb +47 -36
- data/lib/{t2server.rb → t2-server/xml/xpath_cache.rb} +29 -7
- data/t2-server.gemspec +16 -5
- data/test/tc_misc.rb +61 -0
- data/test/tc_perms.rb +17 -1
- data/test/tc_run.rb +164 -34
- data/test/tc_secure.rb +11 -2
- data/test/tc_server.rb +23 -2
- data/test/ts_t2server.rb +10 -8
- data/test/workflows/missing_outputs.t2flow +440 -0
- data/version.yml +3 -3
- metadata +42 -4
data/bin/t2-run-workflow
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (c) 2010-
|
2
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
3
3
|
#
|
4
4
|
# All rights reserved.
|
5
5
|
#
|
@@ -39,18 +39,18 @@ include T2Server::CLI
|
|
39
39
|
# set up options
|
40
40
|
inputs = {}
|
41
41
|
files = {}
|
42
|
-
options = {}
|
43
|
-
conn_params, creds = register_options("Usage: t2-run-workflow [options] "
|
42
|
+
options = {:screds => [], :interactions => :show}
|
43
|
+
conn_params, creds = register_options("Usage: t2-run-workflow [options] "\
|
44
44
|
"server-address") do |opt|
|
45
45
|
opt.separator " Where server-address is the full URI of the server to"
|
46
46
|
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
47
47
|
opt.separator " and [options] can be:"
|
48
|
-
opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If "
|
49
|
-
"this is not specified then the workflow is read from standard "
|
48
|
+
opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If "\
|
49
|
+
"this is not specified then the workflow is read from standard "\
|
50
50
|
"input") do |val|
|
51
51
|
options[:wkf_file] = val.chomp
|
52
52
|
end
|
53
|
-
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to "
|
53
|
+
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to "\
|
54
54
|
"VALUE") do |val|
|
55
55
|
input, value = val.chomp.split(':', 2)
|
56
56
|
inputs[input] = value
|
@@ -60,35 +60,78 @@ conn_params, creds = register_options("Usage: t2-run-workflow [options] " +
|
|
60
60
|
input, filename = val.chomp.split(':', 2)
|
61
61
|
files[input] = filename
|
62
62
|
end
|
63
|
-
opt.on("-
|
63
|
+
opt.on("-I LEVEL", "--interactions=LEVEL", "Show, open or ignore any "\
|
64
|
+
"workflow interactions. LEVEL can be 'show' (the default), which simply "\
|
65
|
+
"lists the interaction URI in the terminal; 'open', which will open the "\
|
66
|
+
"interaction in a Web browser; or 'none', which will not check for "\
|
67
|
+
"interactions from the workflow at all. This should only be set to "\
|
68
|
+
"'none' if you are sure the workflow has no interactions or if you will "\
|
69
|
+
"be handling them in some other way.") do |val|
|
70
|
+
levels = [:show, :open, :none]
|
71
|
+
level = val.downcase.to_sym
|
72
|
+
options[:interactions] = levels.include?(level) ? level : :show
|
73
|
+
end
|
74
|
+
opt.on("-e EXPIRY", "--expiry=EXPIRY", "Set the expiry date/time of this "\
|
64
75
|
"run") do |val|
|
65
76
|
options[:expiry] = Time.parse(val.chomp)
|
66
77
|
end
|
67
|
-
opt.on("-
|
78
|
+
opt.on("-N NAME", "--name=NAME", "Give this run a name. Supported in "\
|
79
|
+
"Taverna Server versions 2.5.0 and up") do |val|
|
80
|
+
options[:name] = val.chomp
|
81
|
+
end
|
82
|
+
opt.on("-c URI::USER:PASS", "--credential=URI::USER:PASS",
|
83
|
+
"Provide a credential for a secure remote service. NOTE :: between URI "\
|
84
|
+
"and credential") do |val|
|
85
|
+
uri, cred = val.chomp.split('::', 2)
|
86
|
+
user, pass = cred.chomp.split(':', 2)
|
87
|
+
options[:screds] << [uri, user, pass]
|
88
|
+
end
|
89
|
+
opt.on("-b BACLAVA", "--baclava-in=BACLAVA", "Set baclava file for input "\
|
68
90
|
"port values") do |val|
|
69
91
|
inputs[:baclava] = val
|
70
92
|
end
|
71
|
-
opt.on("-o", "--baclava-out=BACLAVA", "Return outputs in baclava format."
|
93
|
+
opt.on("-o", "--baclava-out=BACLAVA", "Return outputs in baclava format."\
|
72
94
|
" A filename may be specified or 'out.xml' is used") do |val|
|
73
95
|
options[:baclava_out] = val.chomp
|
74
96
|
end
|
75
|
-
opt.on("-n", "--no-wait", "Do not wait for workflow to finish, return "
|
97
|
+
opt.on("-n", "--no-wait", "Do not wait for workflow to finish, return "\
|
76
98
|
"once it has started running") do |val|
|
77
99
|
options[:no_wait] = true
|
78
100
|
end
|
79
|
-
opt.on("-r", "--output-refs", "Return URIs that point to the data items "
|
101
|
+
opt.on("-r", "--output-refs", "Return URIs that point to the data items "\
|
80
102
|
"of the output rather than the data items themselves.") do |val|
|
81
103
|
options[:output_refs] = val
|
82
104
|
end
|
83
|
-
opt.on("-D", "--delete", "Delete the run from the server when it is "
|
84
|
-
"complete. By default the run and its results are preserved. Note that "
|
105
|
+
opt.on("-D", "--delete", "Delete the run from the server when it is "\
|
106
|
+
"complete. By default the run and its results are preserved. Note that "\
|
85
107
|
"the run will still be deleted when its expiry time is reached") do |val|
|
86
108
|
options[:delete] = val
|
87
109
|
end
|
88
|
-
opt.on("-z", "--zip=FILE", "Get the entire working directory of the run "
|
110
|
+
opt.on("-z", "--zip=FILE", "Get the entire working directory of the run "\
|
89
111
|
"in zip format and save it to the provided filename.") do |val|
|
90
112
|
options[:zip_out] = val.chomp
|
91
113
|
end
|
114
|
+
opt.on("-x", "--exitcode", "Return the exitcode of the run.") do
|
115
|
+
options[:exitcode] = true
|
116
|
+
end
|
117
|
+
opt.on("--stderr", 'Return the "standard error" output of the run.') do
|
118
|
+
options[:stderr] = true
|
119
|
+
end
|
120
|
+
opt.on("--stdout", 'Return the "standard out" output of the run.') do
|
121
|
+
options[:stdout] = true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
if options[:interactions] == :open
|
126
|
+
begin
|
127
|
+
require 'launchy'
|
128
|
+
rescue LoadError
|
129
|
+
puts "\n****\nTo support opening interactions in your Web browser the "\
|
130
|
+
"launchy gem must be installed:\n\n$ gem install launchy\n\n"\
|
131
|
+
"Interaction URIs will be listed here instead. Please copy and paste "\
|
132
|
+
"them into your Web browser to display them.\n****\n\n"
|
133
|
+
options[:interactions] = :show
|
134
|
+
end
|
92
135
|
end
|
93
136
|
|
94
137
|
# read and check server address
|
@@ -107,6 +150,12 @@ begin
|
|
107
150
|
puts "Created run with identifier: #{run.identifier}"
|
108
151
|
puts "Created at #{run.create_time}"
|
109
152
|
|
153
|
+
# set run name
|
154
|
+
if options[:name]
|
155
|
+
run.name = options[:name]
|
156
|
+
puts "Run name set to '#{run.name}'"
|
157
|
+
end
|
158
|
+
|
110
159
|
# set run expiry
|
111
160
|
if options[:expiry]
|
112
161
|
run.expiry=(options[:expiry])
|
@@ -135,43 +184,56 @@ begin
|
|
135
184
|
end
|
136
185
|
end
|
137
186
|
|
187
|
+
# set remote service credentials
|
188
|
+
options[:screds].each do |list|
|
189
|
+
run.add_password_credential(list[0], list[1], list[2])
|
190
|
+
end
|
191
|
+
|
138
192
|
# output baclava?
|
139
193
|
run.request_baclava_output if options[:baclava_out]
|
140
194
|
|
141
|
-
# start run
|
142
|
-
run.start
|
195
|
+
# try to start run
|
196
|
+
unless run.start
|
197
|
+
puts "Run could not be started because the server is already running "\
|
198
|
+
"its configured maximum number of runs. Please try again later."
|
199
|
+
run.delete
|
200
|
+
exit 1
|
201
|
+
end
|
143
202
|
puts "Started at #{run.start_time}"
|
144
203
|
|
145
204
|
# bail out if user doesn't want to wait
|
146
205
|
exit 0 if options[:no_wait]
|
147
206
|
|
148
|
-
# otherwise wait
|
149
|
-
print "Running"
|
207
|
+
# otherwise wait, but list or open notifications if there are any
|
208
|
+
print "Running."
|
150
209
|
until run.finished?
|
151
210
|
sleep(1)
|
211
|
+
unless options[:interactions] == :none
|
212
|
+
run.notifications(:new_requests).each do |note|
|
213
|
+
if options[:interactions] == :open
|
214
|
+
Launchy.open note.uri
|
215
|
+
else
|
216
|
+
puts "\n#{note.uri}\n"
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
152
220
|
print "."
|
153
221
|
$stdout.flush
|
154
222
|
end
|
155
223
|
puts "\nFinished at #{run.finish_time}"
|
156
224
|
|
157
225
|
# get outputs
|
158
|
-
stdout = run.stdout
|
159
|
-
stderr = run.stderr
|
160
226
|
exitcd = run.exitcode
|
161
|
-
puts "Exitcode: #{exitcd}"
|
162
|
-
|
163
|
-
|
227
|
+
puts "Exitcode: #{exitcd}" if options[:exitcode] || exitcd != 0
|
228
|
+
puts "Stdout:\n#{run.stdout}" if options[:stdout]
|
229
|
+
puts "Stderr:\n#{run.stderr}" if options[:stderr]
|
164
230
|
|
165
231
|
if exitcd == 0
|
166
232
|
if options[:baclava_out]
|
167
|
-
|
168
|
-
file.syswrite(run.baclava_output)
|
169
|
-
end
|
233
|
+
run.baclava_output(options[:baclava_out])
|
170
234
|
puts "Baclava file written to '#{options[:baclava_out]}'"
|
171
235
|
elsif options[:zip_out]
|
172
|
-
|
173
|
-
file.syswrite(run.zip_output)
|
174
|
-
end
|
236
|
+
run.zip_output(options[:zip_out])
|
175
237
|
puts "Zip file written to '#{options[:zip_out]}'"
|
176
238
|
else
|
177
239
|
# go through the outputs and print them out
|
data/bin/t2-server-info
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# Copyright (c) 2010-
|
2
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
3
3
|
#
|
4
4
|
# All rights reserved.
|
5
5
|
#
|
@@ -38,15 +38,16 @@ require 'hirb'
|
|
38
38
|
include T2Server::CLI
|
39
39
|
|
40
40
|
# set up options
|
41
|
-
options = {}
|
41
|
+
options = { :list => 0 }
|
42
42
|
conn_params, creds = register_options("Usage: t2-server-info [options] " +
|
43
43
|
"server-address") do |opt|
|
44
44
|
opt.separator " Where server-address is the full URI of the server to"
|
45
45
|
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
46
46
|
opt.separator " and [options] can be:"
|
47
47
|
|
48
|
-
opt.on("-l", "--list", "List details for the runs on this server."
|
49
|
-
|
48
|
+
opt.on("-l", "--list", "List details for the runs on this server. Repeat "\
|
49
|
+
"(e.g. -ll or -lll) to increase the amount of detail shown.") do
|
50
|
+
options[:list] += 1
|
50
51
|
end
|
51
52
|
end
|
52
53
|
|
@@ -61,14 +62,30 @@ begin
|
|
61
62
|
puts " Run limit: #{server.run_limit(creds)}"
|
62
63
|
runs = server.runs(creds)
|
63
64
|
puts "No. of runs: #{runs.length}"
|
64
|
-
if options[:list] && runs.length > 0
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
:
|
71
|
-
:
|
65
|
+
if options[:list] > 0 && runs.length > 0
|
66
|
+
if options[:list] == 1
|
67
|
+
fields = [:identifier]
|
68
|
+
headers = {:identifier => 'Run ID'}
|
69
|
+
lengths = {}
|
70
|
+
elsif options[:list] == 2
|
71
|
+
fields = [:identifier, :status, :expiry]
|
72
|
+
headers = {:identifier => 'Run ID', :status => 'Status',
|
73
|
+
:expiry => 'Expiry time (local)'}
|
74
|
+
lengths = {:status => 11, :expiry => 19}
|
75
|
+
else
|
76
|
+
fields = [:identifier, :name, :status, :expiry]
|
77
|
+
headers = {:identifier => 'Run ID', :name => "Name",
|
78
|
+
:status => 'Status', :expiry => 'Expiry time (local)'}
|
79
|
+
lengths = {:identifier => 11, :name => 25, :status => 11,
|
80
|
+
:expiry => 19}
|
81
|
+
end
|
82
|
+
|
83
|
+
puts Hirb::Helpers::ObjectTable.render(runs,
|
84
|
+
:fields => fields,
|
85
|
+
:headers => headers,
|
86
|
+
:filters => {:expiry => [:strftime, "%H:%M:%S %d/%m/%Y"]},
|
87
|
+
:max_fields => lengths,
|
88
|
+
:description => false)
|
72
89
|
end
|
73
90
|
end
|
74
91
|
rescue RuntimeError => e
|
@@ -0,0 +1,184 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright (c) 2010-2013 The University of Manchester, UK.
|
3
|
+
#
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
# this list of conditions and the following disclaimer in the documentation
|
14
|
+
# and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * Neither the names of The University of Manchester nor the names of its
|
17
|
+
# contributors may be used to endorse or promote products derived from this
|
18
|
+
# software without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
# Author: Robert Haines
|
33
|
+
|
34
|
+
require 'rubygems'
|
35
|
+
require 't2-server-cli'
|
36
|
+
require 'hirb'
|
37
|
+
|
38
|
+
include T2Server::CLI
|
39
|
+
|
40
|
+
# Set up options and workflow inputs.
|
41
|
+
inputs = {}
|
42
|
+
files = {}
|
43
|
+
options = {:number => 5, :backoff => 0, :screds => []}
|
44
|
+
conn_params, creds = register_options("Usage: t2-server-stress [options] "\
|
45
|
+
"server-address") do |opt|
|
46
|
+
opt.separator " Where server-address is the full URI of the server to"
|
47
|
+
opt.separator " connect to, e.g.: http://example.com:8080/taverna"
|
48
|
+
opt.separator " and [options] can be:"
|
49
|
+
|
50
|
+
opt.on("-n NUMBER", "--number=NUMBER", "Number of concurrent runs. "\
|
51
|
+
"Default 5") do |val|
|
52
|
+
options[:number] = val.chomp.to_i
|
53
|
+
end
|
54
|
+
opt.on("-b NUMBER", "--backoff=NUMBER", "Time (in seconds) to back off "\
|
55
|
+
"before starting next run. Default 0") do |val|
|
56
|
+
options[:backoff] = val.chomp.to_i
|
57
|
+
end
|
58
|
+
opt.on("-w WORKFLOW", "--workflow=WORKFLOW", "The workflow to run. If "\
|
59
|
+
"this is not specified then the workflow is read from standard "\
|
60
|
+
"input") do |val|
|
61
|
+
options[:wkf_file] = val.chomp
|
62
|
+
end
|
63
|
+
opt.on("-i INPUT:VALUE", "--input=INPUT:VALUE", "Set input port INPUT to "\
|
64
|
+
"VALUE") do |val|
|
65
|
+
input, value = val.chomp.split(':', 2)
|
66
|
+
inputs[input] = value
|
67
|
+
end
|
68
|
+
opt.on("-f INPUT:FILE", "--input-file=INPUT:FILE",
|
69
|
+
"Set input port INPUT to use the contents of FILE as its input") do |val|
|
70
|
+
input, filename = val.chomp.split(':', 2)
|
71
|
+
files[input] = filename
|
72
|
+
end
|
73
|
+
opt.on("-K", "--keep-runs",
|
74
|
+
"Do not delete the runs at the end of the test") do
|
75
|
+
options[:keep] = true
|
76
|
+
end
|
77
|
+
opt.on("-c URI::USER:PASS", "--credential=URI::USER:PASS",
|
78
|
+
"Provide a credential for a secure remote service. NOTE :: between URI "\
|
79
|
+
"and credential") do |val|
|
80
|
+
uri, cred = val.chomp.split('::', 2)
|
81
|
+
user, pass = cred.chomp.split(':', 2)
|
82
|
+
options[:screds] << [uri, user, pass]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Read and check server address and credentials.
|
87
|
+
uri, creds = parse_address(ARGV.shift, creds)
|
88
|
+
|
89
|
+
# Read workflow and ensure that it is not empty.
|
90
|
+
if options[:wkf_file]
|
91
|
+
wkf = IO.read(options[:wkf_file])
|
92
|
+
else
|
93
|
+
wkf = ARGF.read
|
94
|
+
end
|
95
|
+
exit 1 if wkf == ""
|
96
|
+
|
97
|
+
# Connect to server and check it's in a good state.
|
98
|
+
server = T2Server::Server.new(uri, conn_params)
|
99
|
+
puts "\nConnected to server at #{server.uri}"
|
100
|
+
|
101
|
+
current_runs = server.runs(creds)
|
102
|
+
unless current_runs.length == 0
|
103
|
+
puts "\nServer already has runs on it. Please clear out all runs before "\
|
104
|
+
"running the stress tests."
|
105
|
+
exit 1
|
106
|
+
end
|
107
|
+
|
108
|
+
run_limit = server.run_limit(creds)
|
109
|
+
unless run_limit >= options[:number]
|
110
|
+
puts "\nYou have asked for more concurrent runs than this server has been "\
|
111
|
+
"configured to allow. Please set the number to #{run_limit} or less."
|
112
|
+
exit 1
|
113
|
+
end
|
114
|
+
|
115
|
+
puts "\nInitializing #{options[:number]} runs and setting inputs."
|
116
|
+
runs = []
|
117
|
+
options[:number].times do
|
118
|
+
server.create_run(wkf, creds) do |run|
|
119
|
+
# Set inputs.
|
120
|
+
run.input_ports.each_value do |port|
|
121
|
+
input = port.name
|
122
|
+
if inputs.include? input
|
123
|
+
port.value = inputs[input]
|
124
|
+
elsif files.include? input
|
125
|
+
port.file = files[input]
|
126
|
+
else
|
127
|
+
puts "Input '#{input}' has not been given, exiting."
|
128
|
+
run.delete
|
129
|
+
exit 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
options[:screds].each do |list|
|
134
|
+
run.add_password_credential(list[0], list[1], list[2])
|
135
|
+
end
|
136
|
+
|
137
|
+
runs << run
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
puts "\nStarting runs with #{options[:backoff]} seconds back-off time between."
|
142
|
+
|
143
|
+
w_start = Time.now
|
144
|
+
runs.each do |run|
|
145
|
+
r_start = Time.now
|
146
|
+
while !run.start
|
147
|
+
puts "Server has reached configured maximum of concurrently running "\
|
148
|
+
"runs. Backing off for 10 seconds before retrying..."
|
149
|
+
sleep(10)
|
150
|
+
end
|
151
|
+
r_started = Time.now
|
152
|
+
puts "Run started at #{r_started} and took #{r_started - r_start} seconds to start."
|
153
|
+
sleep options[:backoff] if options[:backoff] > 0
|
154
|
+
end
|
155
|
+
|
156
|
+
puts "\nWaiting for runs to finish."
|
157
|
+
|
158
|
+
while runs.count { |run| run.finished? } < options[:number] do
|
159
|
+
sleep(5)
|
160
|
+
end
|
161
|
+
w_end = Time.now
|
162
|
+
|
163
|
+
puts "\nRuns finished.\n\nRun times:"
|
164
|
+
|
165
|
+
total = 0
|
166
|
+
runs.each do |run|
|
167
|
+
time = run.finish_time - run.start_time
|
168
|
+
total += time
|
169
|
+
puts time
|
170
|
+
end
|
171
|
+
|
172
|
+
average = total / options[:number]
|
173
|
+
puts "\nAverage time: #{average}"
|
174
|
+
w_time = w_end - w_start
|
175
|
+
puts "Wallclock time: #{w_time}"
|
176
|
+
|
177
|
+
unless options[:keep]
|
178
|
+
puts "\nDeleting runs."
|
179
|
+
runs.each do |run|
|
180
|
+
run.delete
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
puts "\nDone."
|