1 | # -*- mode: tcl; indent-tabs-mode: nil -*- |
---|
2 | # ---------------------------------------------------------------------- |
---|
3 | # COMPONENT: task - represents the executable part of a tool |
---|
4 | # |
---|
5 | # This object is an executable version of a Rappture xml file. |
---|
6 | # A tool is a task plus its graphical user interface. Each task |
---|
7 | # resides in an installation directory with other tool resources |
---|
8 | # (libraries, examples, etc.). Each task is defined by its inputs |
---|
9 | # and outputs, and understands the context in which it executes |
---|
10 | # (via exec, submit, mx, etc.). |
---|
11 | # ====================================================================== |
---|
12 | # AUTHOR: Michael McLennan, Purdue University |
---|
13 | # Copyright (c) 2004-2014 HUBzero Foundation, LLC |
---|
14 | # |
---|
15 | # See the file "license.terms" for information on usage and |
---|
16 | # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
---|
17 | # ====================================================================== |
---|
18 | package require BLT |
---|
19 | package require uuid |
---|
20 | |
---|
21 | itcl::class Rappture::Task { |
---|
22 | private method CheckForCachedRunFile { driverFile } |
---|
23 | private method CollectUQResults {} |
---|
24 | private method ExecuteSimulationCommand { cmd } |
---|
25 | private method GetCommand {} |
---|
26 | private method GetDriverFile {} |
---|
27 | private method GetSignal { signal } |
---|
28 | private method GetCacheHelperCommand { driverFile } |
---|
29 | private method GetSimulationCommand { driverFile } |
---|
30 | private method GetUQErrors {} |
---|
31 | private method GetUQSimulationCommand { driverFile } |
---|
32 | private method GetUQTemplateFile {} |
---|
33 | private method IsCacheable {} |
---|
34 | private method IsCacheHelperEligible {} |
---|
35 | private method LogCachedSimulationUsage {} |
---|
36 | private method LogSimulationUsage {} |
---|
37 | private method LogSubmittedSimulationUsage {} |
---|
38 | private method LogUQSimulationUsage {} |
---|
39 | private method SetCpuResourceLimit {} |
---|
40 | |
---|
41 | public variable logger "" |
---|
42 | public variable jobstats Rappture::Task::MiddlewareTime |
---|
43 | public variable resultdir "@default" |
---|
44 | public variable xmlSource "" |
---|
45 | |
---|
46 | constructor {xmlobj installdir args} { # defined below } |
---|
47 | destructor { # defined below } |
---|
48 | |
---|
49 | public method installdir {} { return $_installdir } |
---|
50 | |
---|
51 | public method run {args} |
---|
52 | public method get_uq {args} |
---|
53 | public method abort {} |
---|
54 | public method reset {} |
---|
55 | public method xml {args} |
---|
56 | public method save {xmlobj {name ""}} |
---|
57 | |
---|
58 | protected method OnError {data} |
---|
59 | protected method OnOutput {data} |
---|
60 | protected method Log {args} |
---|
61 | protected method BuildSubmitBoincCommand {tFile toolparamFile params_file} |
---|
62 | protected method BuildSubmitLocalCommand {cmd tFile params_file} |
---|
63 | protected method GetParamsForUQ {} |
---|
64 | |
---|
65 | private variable _xmlobj "" ;# XML object with inputs/outputs |
---|
66 | private variable _origxml "" ;# copy of original XML (for reset) |
---|
67 | private variable _installdir "" ;# installation directory for this tool |
---|
68 | private variable _errorcb "" ;# callback for tool error |
---|
69 | private variable _outputcb "" ;# callback for tool output |
---|
70 | private common jobnum 0 ;# counter for unique job number |
---|
71 | private variable _uq |
---|
72 | |
---|
73 | private variable _job |
---|
74 | |
---|
75 | # get global resources for this tool session |
---|
76 | public proc resources {{option ""}} |
---|
77 | |
---|
78 | public common _resources |
---|
79 | public proc setAppName {name} { set _resources(-appname) $name } |
---|
80 | public proc setHubName {name} { set _resources(-hubname) $name } |
---|
81 | public proc setHubURL {name} { set _resources(-huburl) $name } |
---|
82 | public proc setSession {name} { set _resources(-session) $name } |
---|
83 | public proc setJobPrt {name} { set _resources(-jobprotocol) $name } |
---|
84 | public proc setResultDir {name} { set _resources(-resultdir) $name } |
---|
85 | public proc setCacheHosts {name} { set _resources(-cachehosts) $name } |
---|
86 | public proc setCacheUser {name} { set _resources(-cacheuser) $name } |
---|
87 | public proc setCacheWriteHost {name} { set _resources(-cachewritehost) $name } |
---|
88 | |
---|
89 | # default method for -jobstats control |
---|
90 | public proc MiddlewareTime {args} |
---|
91 | } |
---|
92 | |
---|
93 | # must use this name -- plugs into Rappture::resources::load |
---|
94 | proc task_init_resources {} { |
---|
95 | Rappture::resources::register \ |
---|
96 | application_name Rappture::Task::setAppName \ |
---|
97 | application_id Rappture::Task::setAppId \ |
---|
98 | hub_name Rappture::Task::setHubName \ |
---|
99 | hub_url Rappture::Task::setHubURL \ |
---|
100 | session_token Rappture::Task::setSession \ |
---|
101 | job_protocol Rappture::Task::setJobPrt \ |
---|
102 | results_directory Rappture::Task::setResultDir \ |
---|
103 | cache_hosts Rappture::Task::setCacheHosts \ |
---|
104 | cache_user Rappture::Task::setCacheUser \ |
---|
105 | cache_write_host Rappture::Task::setCacheWriteHost |
---|
106 | } |
---|
107 | |
---|
108 | # ---------------------------------------------------------------------- |
---|
109 | # CONSTRUCTOR |
---|
110 | # ---------------------------------------------------------------------- |
---|
111 | itcl::body Rappture::Task::constructor {xmlobj installdir args} { |
---|
112 | if {![Rappture::library isvalid $xmlobj]} { |
---|
113 | error "bad value \"$xmlobj\": should be Rappture::Library" |
---|
114 | } |
---|
115 | set _xmlobj $xmlobj |
---|
116 | |
---|
117 | # stash a copy of the original XML for later "reset" operations |
---|
118 | set _origxml [Rappture::LibraryObj ::#auto "<?xml version=\"1.0\"?><run/>"] |
---|
119 | $_origxml copy "" from $_xmlobj "" |
---|
120 | |
---|
121 | if {![file exists $installdir]} { |
---|
122 | error "directory \"$installdir\" doesn't exist" |
---|
123 | } |
---|
124 | set _installdir $installdir |
---|
125 | package require http |
---|
126 | package require tls |
---|
127 | http::register https 443 [list ::tls::socket -tls1 0 -ssl2 0 -ssl3 0] |
---|
128 | |
---|
129 | eval configure $args |
---|
130 | } |
---|
131 | |
---|
132 | # ---------------------------------------------------------------------- |
---|
133 | # DESTRUCTOR |
---|
134 | # ---------------------------------------------------------------------- |
---|
135 | itcl::body Rappture::Task::destructor {} { |
---|
136 | itcl::delete object $_origxml |
---|
137 | } |
---|
138 | |
---|
139 | # ---------------------------------------------------------------------- |
---|
140 | # USAGE: resources ?-option? |
---|
141 | # |
---|
142 | # Clients use this to query information about the tool. |
---|
143 | # ---------------------------------------------------------------------- |
---|
144 | itcl::body Rappture::Task::resources {{option ""}} { |
---|
145 | if {$option == ""} { |
---|
146 | return [array get _resources] |
---|
147 | } |
---|
148 | if {[info exists _resources($option)]} { |
---|
149 | return $_resources($option) |
---|
150 | } |
---|
151 | return "" |
---|
152 | } |
---|
153 | |
---|
154 | itcl::body Rappture::Task::GetSignal {code} { |
---|
155 | set signals { |
---|
156 | xxx HUP INT QUIT ILL TRAP ABRT BUS FPE KILL USR1 SEGV |
---|
157 | USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN |
---|
158 | TTOU URG XCPU XFSZ VTALRM PROF WINCH POLL PWR SYS |
---|
159 | RTMIN RTMIN+1 RTMIN+2 RTMIN+3 RTMAX-3 RTMAX-2 RTMAX-1 RTMAX |
---|
160 | } |
---|
161 | set sigNum [expr $code - 128] |
---|
162 | if { $sigNum > 0 && $sigNum < [llength $signals] } { |
---|
163 | return [lindex $signals $sigNum] |
---|
164 | } |
---|
165 | return "unknown exit code \"$code\"" |
---|
166 | } |
---|
167 | |
---|
168 | itcl::body Rappture::Task::get_uq {args} { |
---|
169 | foreach {path val} $args { |
---|
170 | if {$path == "-uq_type"} { |
---|
171 | set _uq(type) $val |
---|
172 | } elseif {$path == "-uq_args"} { |
---|
173 | set _uq(args) $val |
---|
174 | } |
---|
175 | } |
---|
176 | #set varlist [$_xmlobj uq_get_vars] |
---|
177 | foreach {varlist num} [$_xmlobj uq_get_vars] break |
---|
178 | return [Rappture::UQ ::#auto $varlist $num $_uq(type) $_uq(args)] |
---|
179 | } |
---|
180 | |
---|
181 | # ---------------------------------------------------------------------- |
---|
182 | # USAGE: run ?<path1> <value1> <path2> <value2> ...? ?-output <callbk>? |
---|
183 | # |
---|
184 | # This method causes the tool to run. A "driver.xml" file is created |
---|
185 | # as the input for the run. That file is fed to the executable |
---|
186 | # according to the <tool><command> string, and the job is executed. |
---|
187 | # |
---|
188 | # Any "<path> <value>" arguments are used to override the current |
---|
189 | # settings from the GUI. This is useful, for example, when filling |
---|
190 | # in missing simulation results from the analyzer. |
---|
191 | # |
---|
192 | # If the -output argument is included, then the next arg is a |
---|
193 | # callback command for output messages. Any output that comes in |
---|
194 | # while the tool is running is sent back to the caller, so the user |
---|
195 | # can see progress running the tool. |
---|
196 | # |
---|
197 | # Returns a list of the form {status result}, where status is an |
---|
198 | # integer status code (0=success) and result is the output from the |
---|
199 | # simulator. Successful output is something like {0 run1293921.xml}, |
---|
200 | # where 0=success and run1293921.xml is the name of the file containing |
---|
201 | # results. |
---|
202 | # ---------------------------------------------------------------------- |
---|
203 | itcl::body Rappture::Task::run {args} { |
---|
204 | global env errorInfo |
---|
205 | |
---|
206 | # |
---|
207 | # Make sure that we save the proper application name. Actually, the |
---|
208 | # best place to get this information is straight from the "installtool" |
---|
209 | # script, but just in case we have an older tool, we should insert the |
---|
210 | # tool name from the resources config file. |
---|
211 | # |
---|
212 | if {[info exists _resources(-appname)] && $_resources(-appname) ne "" && |
---|
213 | [$_xmlobj get tool.name] eq ""} { |
---|
214 | $_xmlobj put tool.name $_resources(-appname) |
---|
215 | } |
---|
216 | |
---|
217 | # if there are any args, use them to override parameters |
---|
218 | set _errorcb "" |
---|
219 | set _outputcb "" |
---|
220 | set _uq(type) "" |
---|
221 | set _uq(tFile) "" |
---|
222 | set _uq(toolparamFile) "" |
---|
223 | set _uq(paramsFile) "" |
---|
224 | foreach {path val} $args { |
---|
225 | if {$path == "-stdout"} { |
---|
226 | set _outputcb $val |
---|
227 | } elseif {$path == "-stderr"} { |
---|
228 | set _errorcb $val |
---|
229 | } elseif {$path == "-uq_type"} { |
---|
230 | set _uq(type) $val |
---|
231 | } elseif {$path == "-uq_args"} { |
---|
232 | set _uq(args) $val |
---|
233 | } elseif {$path != "-output"} { |
---|
234 | $_xmlobj put $path.current $val |
---|
235 | } |
---|
236 | } |
---|
237 | foreach {path val} $args { |
---|
238 | if {$path == "-output"} { |
---|
239 | if {$_outputcb == ""} { |
---|
240 | set _outputcb $val |
---|
241 | } |
---|
242 | } |
---|
243 | } |
---|
244 | |
---|
245 | # Initialize job array variables |
---|
246 | array set _job { |
---|
247 | control "" |
---|
248 | exitcode 0 |
---|
249 | mesg "" |
---|
250 | runfile "" |
---|
251 | stderr "" |
---|
252 | stdout "" |
---|
253 | success 0 |
---|
254 | xmlobj "" |
---|
255 | } |
---|
256 | |
---|
257 | SetCpuResourceLimit |
---|
258 | |
---|
259 | set helperEligible [IsCacheHelperEligible] |
---|
260 | |
---|
261 | set driverFile [GetDriverFile] |
---|
262 | set cached 0 |
---|
263 | if { [IsCacheable] } { |
---|
264 | puts stderr "Cache checking: [time { |
---|
265 | set cached [CheckForCachedRunFile $driverFile] |
---|
266 | } ]" |
---|
267 | puts stderr "checking cached=$cached" |
---|
268 | } |
---|
269 | if { !$cached } { |
---|
270 | if { $_uq(type) != "" } { |
---|
271 | set _uq(tFile) [GetUQTemplateFile] |
---|
272 | } |
---|
273 | global env |
---|
274 | if { $_uq(type) == "" } { |
---|
275 | if { $helperEligible } { |
---|
276 | set cmd [GetCacheHelperCommand $driverFile] |
---|
277 | } else { |
---|
278 | set cmd [GetSimulationCommand $driverFile] |
---|
279 | } |
---|
280 | set ::env(RAPPTURE_UQ) False |
---|
281 | } else { |
---|
282 | set cmd [GetUQSimulationCommand $driverFile] |
---|
283 | set ::env(RAPPTURE_UQ) True |
---|
284 | } |
---|
285 | if { $cmd == "" } { |
---|
286 | puts stderr "cmd is empty" |
---|
287 | append mesg "There is no command specified by\n\n" |
---|
288 | append mesg " <command>\n" |
---|
289 | append mesg " </command>\n\n" |
---|
290 | append mesg "in the tool.xml file." |
---|
291 | return [list 1 $mesg] |
---|
292 | } |
---|
293 | Rappture::rusage mark |
---|
294 | if { ![ExecuteSimulationCommand $cmd] } { |
---|
295 | return [list 1 $_job(mesg)] |
---|
296 | } |
---|
297 | if { $_uq(type) != "" } { |
---|
298 | LogUQSimulationUsage |
---|
299 | } elseif { [resources -jobprotocol] == "submit" } { |
---|
300 | LogSubmittedSimulationUsage |
---|
301 | } else { |
---|
302 | LogSimulationUsage |
---|
303 | } |
---|
304 | } else { |
---|
305 | LogCachedSimulationUsage |
---|
306 | } |
---|
307 | if { $_uq(tFile) ne "" } { |
---|
308 | file delete -force -- $_uq(tFile) |
---|
309 | } |
---|
310 | if { $_uq(toolparamFile) ne "" } { |
---|
311 | file delete -force -- $_uq(toolparamFile) |
---|
312 | } |
---|
313 | if { $_uq(paramsFile) ne "" } { |
---|
314 | file delete -force -- $_uq(paramsFile) |
---|
315 | } |
---|
316 | if { $_job(success) } { |
---|
317 | file delete -force -- $driverFile |
---|
318 | Log run finished |
---|
319 | return [list 0 $_job(xmlobj)] |
---|
320 | } else { |
---|
321 | # See if the job was aborted. |
---|
322 | if {[regexp {^KILLED} $_job(control)]} { |
---|
323 | Log run aborted |
---|
324 | return [list 1 "ABORT"] |
---|
325 | } |
---|
326 | Log run failed [list 0 $_job(mesg)] |
---|
327 | return [list 1 $_job(mesg)] |
---|
328 | } |
---|
329 | } |
---|
330 | |
---|
331 | # ---------------------------------------------------------------------- |
---|
332 | # Turn the command string from tool.xml into the proper syntax to use |
---|
333 | # with a submit parameter sweep with a temlate file. Proper quoting |
---|
334 | # of the template file is necessary to prevent submit from being too smart |
---|
335 | # and converting it to a full pathname. |
---|
336 | # ---------------------------------------------------------------------- |
---|
337 | itcl::body Rappture::Task::BuildSubmitBoincCommand {tFile toolparamFile params_file} { |
---|
338 | set toolId [$_xmlobj get tool.id] |
---|
339 | set toolVers [$_xmlobj get tool.version.application.revision] |
---|
340 | set newcmd "submit --venue boinc --progress submit --runName=puq --inputfile @:$tFile --data $params_file --env TOOL_PARAMETERS=$toolparamFile ${toolId}_r${toolVers} -w headless" |
---|
341 | |
---|
342 | return $newcmd |
---|
343 | } |
---|
344 | |
---|
345 | itcl::body Rappture::Task::BuildSubmitLocalCommand {cmd tFile params_file} { |
---|
346 | set quote_next 0 |
---|
347 | set newcmd "submit --local --progress submit --runName=puq --inputfile @:$tFile --data $params_file" |
---|
348 | set cmds [split $cmd " "] |
---|
349 | for {set i 0} {$i < [llength $cmds]} {incr i} { |
---|
350 | set arg [lindex $cmds $i] |
---|
351 | if {$quote_next == 1} { |
---|
352 | set nc [string range $arg 0 0] |
---|
353 | if {$nc != "\""} { |
---|
354 | set arg "\"\\\"$arg\\\"\"" |
---|
355 | } |
---|
356 | } |
---|
357 | if {$arg == "--eval"} { |
---|
358 | set quote_next 1 |
---|
359 | } else { |
---|
360 | set quote_next 0 |
---|
361 | } |
---|
362 | if {$arg == "@driver"} { |
---|
363 | set arg "\"\\\"$tFile\\\"\"" |
---|
364 | } |
---|
365 | append newcmd " " $arg |
---|
366 | } |
---|
367 | regsub -all @driver $newcmd $tFile newcmd |
---|
368 | |
---|
369 | return $newcmd |
---|
370 | } |
---|
371 | |
---|
372 | # ---------------------------------------------------------------------- |
---|
373 | # USAGE: abort |
---|
374 | # |
---|
375 | # Clients use this during a "run" to abort the current job. |
---|
376 | # Kills the job and forces the "run" method to return. |
---|
377 | # ---------------------------------------------------------------------- |
---|
378 | itcl::body Rappture::Task::abort {} { |
---|
379 | Log run abort |
---|
380 | set _job(control) "abort" |
---|
381 | } |
---|
382 | |
---|
383 | # ---------------------------------------------------------------------- |
---|
384 | # USAGE: reset |
---|
385 | # |
---|
386 | # Resets all input values to their defaults. Sometimes used just |
---|
387 | # before a run to reset to a clean state. |
---|
388 | # ---------------------------------------------------------------------- |
---|
389 | itcl::body Rappture::Task::reset {} { |
---|
390 | $_xmlobj copy "" from $_origxml "" |
---|
391 | foreach path [Rappture::entities -as path $_xmlobj input] { |
---|
392 | if {[$_xmlobj element -as type $path.default] ne ""} { |
---|
393 | set defval [$_xmlobj get $path.default] |
---|
394 | $_xmlobj put $path.current $defval |
---|
395 | } |
---|
396 | } |
---|
397 | } |
---|
398 | |
---|
399 | # ---------------------------------------------------------------------- |
---|
400 | # USAGE: xml <subcommand> ?<arg> <arg> ...? |
---|
401 | # USAGE: xml object |
---|
402 | # |
---|
403 | # Used by clients to manipulate the underlying XML data for this |
---|
404 | # tool. The <subcommand> can be any operation supported by a |
---|
405 | # Rappture::library object. Clients can also request the XML object |
---|
406 | # directly by using the "object" subcommand. |
---|
407 | # ---------------------------------------------------------------------- |
---|
408 | itcl::body Rappture::Task::xml {args} { |
---|
409 | if {"object" == $args} { |
---|
410 | return $_xmlobj |
---|
411 | } |
---|
412 | return [eval $_xmlobj $args] |
---|
413 | } |
---|
414 | |
---|
415 | # ---------------------------------------------------------------------- |
---|
416 | # USAGE: save <xmlobj> ?<filename>? |
---|
417 | # |
---|
418 | # Used by clients to save the contents of an <xmlobj> representing |
---|
419 | # a run out to the given file. If <filename> is not specified, then |
---|
420 | # it uses the -resultsdir and other settings to do what Rappture |
---|
421 | # would normally do with the output. |
---|
422 | # ---------------------------------------------------------------------- |
---|
423 | itcl::body Rappture::Task::save {xmlobj {filename ""}} { |
---|
424 | if {$filename eq ""} { |
---|
425 | |
---|
426 | # If there's a results_directory defined in the resources file, |
---|
427 | # then move the run.xml file there for storage. |
---|
428 | |
---|
429 | set rdir "" |
---|
430 | if {$resultdir eq "@default"} { |
---|
431 | if {[info exists _resources(-resultdir)]} { |
---|
432 | set rdir $_resources(-resultdir) |
---|
433 | } else { |
---|
434 | global rapptureInfo |
---|
435 | set rdir $rapptureInfo(cwd) |
---|
436 | } |
---|
437 | } elseif {$resultdir ne ""} { |
---|
438 | set rdir $resultdir |
---|
439 | } |
---|
440 | |
---|
441 | # use the runfile name generated by the last run |
---|
442 | if {$_job(runfile) ne ""} { |
---|
443 | set filename [file join $rdir [file tail $_job(runfile)]] |
---|
444 | } else { |
---|
445 | set filename [file join $rdir run.xml] |
---|
446 | } |
---|
447 | } |
---|
448 | |
---|
449 | # add any last-minute metadata |
---|
450 | $xmlobj put output.time [clock format [clock seconds]] |
---|
451 | |
---|
452 | $xmlobj put tool.version.rappture.version $::Rappture::version |
---|
453 | $xmlobj put tool.version.rappture.revision $::Rappture::build |
---|
454 | $xmlobj put output.filename $filename |
---|
455 | $xmlobj put output.version $Rappture::version |
---|
456 | |
---|
457 | if {[info exists ::tcl_platform(user)]} { |
---|
458 | $xmlobj put output.user $::tcl_platform(user) |
---|
459 | } |
---|
460 | |
---|
461 | # save the output |
---|
462 | set rdir [file dirname $filename] |
---|
463 | file mkdir $rdir |
---|
464 | |
---|
465 | set fid [open $filename w] |
---|
466 | puts $fid "<?xml version=\"1.0\"?>" |
---|
467 | puts $fid [$xmlobj xml] |
---|
468 | close $fid |
---|
469 | |
---|
470 | Log output saved in $filename |
---|
471 | } |
---|
472 | |
---|
473 | # ---------------------------------------------------------------------- |
---|
474 | # USAGE: OnOutput <data> |
---|
475 | # |
---|
476 | # Used internally to send each bit of output <data> coming from the |
---|
477 | # tool onto the caller, so the user can see progress. |
---|
478 | # ---------------------------------------------------------------------- |
---|
479 | itcl::body Rappture::Task::OnOutput {data} { |
---|
480 | if {[string length $_outputcb] > 0} { |
---|
481 | uplevel #0 $_outputcb [list $data] |
---|
482 | } |
---|
483 | } |
---|
484 | |
---|
485 | # ---------------------------------------------------------------------- |
---|
486 | # USAGE: OnError <data> |
---|
487 | # |
---|
488 | # Used internally to send each bit of error <data> coming from the |
---|
489 | # tool onto the caller, so the user can see progress. |
---|
490 | # ---------------------------------------------------------------------- |
---|
491 | itcl::body Rappture::Task::OnError {data} { |
---|
492 | if {[string length $_errorcb] > 0} { |
---|
493 | uplevel #0 $_errorcb [list $data] |
---|
494 | } |
---|
495 | } |
---|
496 | |
---|
497 | # ---------------------------------------------------------------------- |
---|
498 | # USAGE: Log <cmd> <arg> <arg> ... |
---|
499 | # |
---|
500 | # Used internally to log interesting events during the run. If the |
---|
501 | # -logger option is set (to Rappture::Logger::log, or something like |
---|
502 | # that), then the arguments to this method are passed along to the |
---|
503 | # logger and written out to a log file. Logging is off by default, |
---|
504 | # so this method does nothing unless -logger is set. |
---|
505 | # ---------------------------------------------------------------------- |
---|
506 | itcl::body Rappture::Task::Log {args} { |
---|
507 | if {[string length $logger] > 0} { |
---|
508 | uplevel #0 $logger [list $args] |
---|
509 | } |
---|
510 | } |
---|
511 | |
---|
512 | # ---------------------------------------------------------------------- |
---|
513 | # USAGE: MiddlewareTime <key> <value> ... |
---|
514 | # |
---|
515 | # Used as the default method for reporting job status information. |
---|
516 | # Implements the old HUBzero method of reporting job status info to |
---|
517 | # stderr, which can then be picked up by the tool session container. |
---|
518 | # Most tools use the "submit" command, which talks directly to a |
---|
519 | # database to log job information, so this isn't really needed. But |
---|
520 | # it doesn't hurt to have this and it can be useful in some cases. |
---|
521 | # ---------------------------------------------------------------------- |
---|
522 | itcl::body Rappture::Task::MiddlewareTime {args} { |
---|
523 | set line "MiddlewareTime:" |
---|
524 | foreach {key val} $args { |
---|
525 | append line " $key=$val" |
---|
526 | } |
---|
527 | puts stderr $line |
---|
528 | } |
---|
529 | |
---|
530 | itcl::body Rappture::Task::IsCacheable {} { |
---|
531 | if { ![info exists _resources(-cachehosts)] || |
---|
532 | $_resources(-cachehosts) == "" } { |
---|
533 | puts stderr cachehosts=[info exists _resources(-cachehosts)] |
---|
534 | return 0 |
---|
535 | } |
---|
536 | global env |
---|
537 | if { [info exists env(RAPPTURE_CACHE_OVERRIDE)] } { |
---|
538 | set state $env(RAPPTURE_CACHE_OVERRIDE) |
---|
539 | } else { |
---|
540 | set state [$_xmlobj get "tool.cache"] |
---|
541 | } |
---|
542 | if { $state ne "" } { |
---|
543 | puts stderr "cache tag is \"$state\"" |
---|
544 | } |
---|
545 | if { $state eq "" || ![string is boolean $state] } { |
---|
546 | return 1; # Default is to allow caching. |
---|
547 | } |
---|
548 | return $state |
---|
549 | } |
---|
550 | |
---|
551 | itcl::body Rappture::Task::IsCacheHelperEligible {} { |
---|
552 | global env |
---|
553 | if { ![info exists env(IONHELPER_ALLOWED)] } { |
---|
554 | set helperEligible 0 |
---|
555 | } else { |
---|
556 | if { $env(IONHELPER_ALLOWED) ne "1" } { |
---|
557 | set helperEligible 0 |
---|
558 | } else { |
---|
559 | if { $_uq(type) == "" } { |
---|
560 | # puts stderr "cache_user exists = [info exists _resources(-cacheuser)]" |
---|
561 | # puts stderr "cache_write_host exists = [info exists _resources(-cachewritehost)]" |
---|
562 | if { ![info exists _resources(-cacheuser)] || ![info exists _resources(-cachewritehost)] } { |
---|
563 | set helperEligible 0 |
---|
564 | } else { |
---|
565 | if { ![info exists env(USER)] } { |
---|
566 | set helperEligible 0 |
---|
567 | } else { |
---|
568 | # puts stderr "env(USER) = $env(USER)" |
---|
569 | # puts stderr "cache_user = $_resources(-cacheuser)" |
---|
570 | if { $env(USER) eq $_resources(-cacheuser) } { |
---|
571 | set helperEligible 0 |
---|
572 | } else { |
---|
573 | set toolId [$_xmlobj get tool.id] |
---|
574 | set toolVers [$_xmlobj get tool.version.application.revision] |
---|
575 | set toolDir [$_xmlobj get tool.version.application.directory(top)] |
---|
576 | set verifyDir [file join / apps ${toolId} r${toolVers}] |
---|
577 | # puts stderr "toolDir = $toolDir" |
---|
578 | # puts stderr "verifyDir = $verifyDir" |
---|
579 | if { $toolDir eq $verifyDir } { |
---|
580 | if { [ catch { file readlink [file join / apps ${toolId} current] } currentVers ] != 0 } { |
---|
581 | set helperEligible 0 |
---|
582 | } else { |
---|
583 | # puts stderr "currentVers = $currentVers" |
---|
584 | if { "r$toolVers" eq $currentVers } { |
---|
585 | set helperEligible 1 |
---|
586 | } else { |
---|
587 | set helperEligible 0 |
---|
588 | } |
---|
589 | } |
---|
590 | } else { |
---|
591 | set helperEligible 0 |
---|
592 | } |
---|
593 | } |
---|
594 | } |
---|
595 | } |
---|
596 | } else { |
---|
597 | set helperEligible 0 |
---|
598 | } |
---|
599 | } |
---|
600 | } |
---|
601 | # puts stderr "helperEligible = $helperEligible" |
---|
602 | |
---|
603 | return $helperEligible |
---|
604 | } |
---|
605 | |
---|
606 | # |
---|
607 | # Send the list of parameters to a python program so it can call PUQ |
---|
608 | # and get a CSV file containing the parameter values to use for the runs. |
---|
609 | itcl::body Rappture::Task::GetParamsForUQ {} { |
---|
610 | set pid [pid] |
---|
611 | # puts "puq.sh get_params $pid $_uq(varlist) $_uq(type) $_uq(args)" |
---|
612 | if {[catch { |
---|
613 | exec puq.sh get_params $pid $_uq(varlist) $_uq(type) $_uq(args) |
---|
614 | } errs] != 0 } { |
---|
615 | error "get_params.py failed: $errs\n[GetUQErrors]" |
---|
616 | } |
---|
617 | return "params${pid}.csv" |
---|
618 | } |
---|
619 | |
---|
620 | itcl::body Rappture::Task::SetCpuResourceLimit {} { |
---|
621 | # Set limits for cpu time |
---|
622 | set limit [$_xmlobj get tool.limits.cputime] |
---|
623 | if { $limit == "unlimited" } { |
---|
624 | set limit 43200; # 12 hours |
---|
625 | } else { |
---|
626 | if { [scan $limit "%d" dum] != 1 } { |
---|
627 | set limit 14400; # 4 hours by default |
---|
628 | } elseif { $limit > 43200 } { |
---|
629 | set limit 43200; # limit to 12 hrs. |
---|
630 | } elseif { $limit < 10 } { |
---|
631 | set limit 10; # lower bound is 10 seconds. |
---|
632 | } |
---|
633 | } |
---|
634 | Rappture::rlimit set cputime $limit |
---|
635 | } |
---|
636 | |
---|
637 | # Write out the driver.xml file for the tool |
---|
638 | itcl::body Rappture::Task::GetDriverFile {} { |
---|
639 | global rapptureInfo |
---|
640 | set fileName [file join $rapptureInfo(cwd) "driver[pid].xml"] |
---|
641 | # |
---|
642 | # Remove existing <meta> section |
---|
643 | $_xmlobj remove "meta" |
---|
644 | # Copy original <meta> section |
---|
645 | $_xmlobj copy "meta" from $_origxml "meta" |
---|
646 | # Add new <meta> entry |
---|
647 | if { $xmlSource != "" } { |
---|
648 | set identifier [uuid::uuid generate] |
---|
649 | $_xmlobj put meta.driver($identifier).source $xmlSource |
---|
650 | $_xmlobj put meta.driver($identifier).version $::Rappture::build |
---|
651 | $_xmlobj put meta.driver($identifier).time [clock format [clock seconds]] |
---|
652 | if { $xmlSource == "rapptureUI" } { |
---|
653 | $_xmlobj put meta.generated human |
---|
654 | } |
---|
655 | set generated [$_xmlobj get meta.generated] |
---|
656 | if { $generated == "" } { |
---|
657 | $_xmlobj put meta.generated human |
---|
658 | } |
---|
659 | set generated [$_xmlobj get meta.generated] |
---|
660 | global env |
---|
661 | set ::env(RAPPTURE_GENERATED) $generated |
---|
662 | if {[info exists env(RAPPTURE_GENERATED_FILE)]} { |
---|
663 | set f [open $env(RAPPTURE_GENERATED_FILE) w] |
---|
664 | puts $f "generated $generated" |
---|
665 | close $f |
---|
666 | } |
---|
667 | } |
---|
668 | # |
---|
669 | if { [catch { |
---|
670 | set f [open $fileName w] |
---|
671 | puts $f "<?xml version=\"1.0\"?>" |
---|
672 | puts $f [$_xmlobj xml] |
---|
673 | close $f |
---|
674 | } errs] != 0 } { |
---|
675 | error "can't create driver file \"$fileName\": $errs" |
---|
676 | } |
---|
677 | return $fileName |
---|
678 | } |
---|
679 | |
---|
680 | itcl::body Rappture::Task::GetCacheHelperCommand { driverFile } { |
---|
681 | set cmd "" |
---|
682 | set helperDriverDir [file join / var ion drivers] |
---|
683 | if { [file exists $helperDriverDir] } { |
---|
684 | set cacheHelperCommand [file join / apps bin iondrive] |
---|
685 | if { [file exists $cacheHelperCommand] } { |
---|
686 | file copy -force $driverFile $helperDriverDir |
---|
687 | set cmd $cacheHelperCommand |
---|
688 | } |
---|
689 | } |
---|
690 | |
---|
691 | return $cmd |
---|
692 | } |
---|
693 | |
---|
694 | itcl::body Rappture::Task::GetCommand { } { |
---|
695 | set cmd [$_xmlobj get tool.command] |
---|
696 | regsub -all @tool $cmd $_installdir cmd |
---|
697 | set cmd [string trimleft $cmd " "] |
---|
698 | return $cmd |
---|
699 | } |
---|
700 | |
---|
701 | itcl::body Rappture::Task::GetSimulationCommand { driverFile } { |
---|
702 | set cmd [GetCommand] |
---|
703 | if { $cmd == "" } { |
---|
704 | return "" |
---|
705 | } |
---|
706 | regsub -all @driver $cmd $driverFile cmd |
---|
707 | |
---|
708 | switch -glob -- [resources -jobprotocol] { |
---|
709 | "submit*" { |
---|
710 | # if job_protocol is "submit", then use use submit command |
---|
711 | set cmd "submit --local $cmd" |
---|
712 | } |
---|
713 | "mx" { |
---|
714 | # metachory submission |
---|
715 | set cmd "mx $cmd" |
---|
716 | } |
---|
717 | "exec" { |
---|
718 | # default -- nothing special |
---|
719 | } |
---|
720 | } |
---|
721 | return $cmd |
---|
722 | } |
---|
723 | |
---|
724 | itcl::body Rappture::Task::GetUQSimulationCommand { driverFile } { |
---|
725 | set cmd [GetCommand] |
---|
726 | if { $cmd == "" } { |
---|
727 | return "" |
---|
728 | } |
---|
729 | set _uq(paramsFile) [GetParamsForUQ] |
---|
730 | # set cmd [BuildSubmitBoincCommand $_uq(tFile) $_uq(toolparamFile) $_uq(paramsFile)] |
---|
731 | set cmd [BuildSubmitLocalCommand $cmd $_uq(tFile) $_uq(paramsFile)] |
---|
732 | |
---|
733 | file delete -force puq |
---|
734 | |
---|
735 | return $cmd |
---|
736 | } |
---|
737 | |
---|
738 | itcl::body Rappture::Task::GetUQTemplateFile {} { |
---|
739 | global rapptureInfo |
---|
740 | # Copy xml into a new file |
---|
741 | set templateFile "template[pid].xml" |
---|
742 | set f [open $templateFile w] |
---|
743 | puts $f "<?xml version=\"1.0\"?>" |
---|
744 | puts $f [$_xmlobj xml] |
---|
745 | close $f |
---|
746 | |
---|
747 | # Return a list of the UQ variables and their PDFs. |
---|
748 | # Also turns $uq(tFile) into a template file. |
---|
749 | set _uq(varlist) [lindex [$_xmlobj uq_get_vars $templateFile] 0] |
---|
750 | set _uq(tFile) $templateFile |
---|
751 | |
---|
752 | # Create toolparameter file |
---|
753 | set toolParameterFile "toolParameter[pid].hz" |
---|
754 | set f [open $toolParameterFile w] |
---|
755 | puts $f "file(execute):$templateFile" |
---|
756 | close $f |
---|
757 | |
---|
758 | set _uq(toolparamFile) $toolParameterFile |
---|
759 | |
---|
760 | return $templateFile |
---|
761 | } |
---|
762 | |
---|
763 | itcl::body Rappture::Task::ExecuteSimulationCommand { cmd } { |
---|
764 | |
---|
765 | set _job(runfile) "" |
---|
766 | set _job(success) 0 |
---|
767 | set _job(exitcode) 0 |
---|
768 | |
---|
769 | # Step 1. Write the command into the run file. |
---|
770 | $_xmlobj put tool.execute $cmd |
---|
771 | |
---|
772 | Log run started |
---|
773 | Rappture::rusage mark |
---|
774 | |
---|
775 | # Step 2. Check if it is a special case "ECHO" command which always |
---|
776 | # succeeds. |
---|
777 | if { [string compare -nocase -length 5 $cmd "ECHO "] == 0 } { |
---|
778 | set _job(stdout) [string range $cmd 5 end] |
---|
779 | set _job(success) 1 |
---|
780 | set _job(exitcode) 0 |
---|
781 | set _job(mesg) "" |
---|
782 | return 1; # Success |
---|
783 | } |
---|
784 | |
---|
785 | # Step 3. Execute the command, collecting its stdout and stderr. |
---|
786 | catch { |
---|
787 | eval blt::bgexec [list [itcl::scope _job(control)]] \ |
---|
788 | -keepnewline yes \ |
---|
789 | -killsignal SIGTERM \ |
---|
790 | -onerror [list [itcl::code $this OnError]] \ |
---|
791 | -onoutput [list [itcl::code $this OnOutput]] \ |
---|
792 | -output [list [itcl::scope _job(stdout)]] \ |
---|
793 | -error [list [itcl::scope _job(stderr)]] \ |
---|
794 | $cmd |
---|
795 | } result |
---|
796 | |
---|
797 | # Step 4. Check the token and the exit code. |
---|
798 | set logmesg $result |
---|
799 | foreach { token _job(pid) _job(exitcode) mesg } $_job(control) break |
---|
800 | if { $token == "EXITED" } { |
---|
801 | if { $_job(exitcode) != 0 } { |
---|
802 | # This means that the program exited normally but returned a |
---|
803 | # non-zero exitcode. Consider this an invalid result from the |
---|
804 | # program. Append the stderr from the program to the message. |
---|
805 | if {$_job(exitcode) > 128} { |
---|
806 | set logmesg "Program signaled: signal was [GetSignal $_job(exitcode)]" |
---|
807 | } else { |
---|
808 | set logmesg "Program finished: non-zero exit code is $_job(exitcode)" |
---|
809 | } |
---|
810 | set _job(mesg) "$logmesg\n\n$_job(stderr)" |
---|
811 | Log run failed [list $logmesg] |
---|
812 | return 0; # Fail. |
---|
813 | } |
---|
814 | # Successful program termination with exit code of 0. |
---|
815 | } elseif { $token == "abort" } { |
---|
816 | # The user pressed the abort button. |
---|
817 | |
---|
818 | set logmesg "Program terminated by user." |
---|
819 | Log run failed [list $logmesg] |
---|
820 | set _job(mesg) "$logmesg\n\n$_job(stdout)" |
---|
821 | return 0; # Fail |
---|
822 | } else { |
---|
823 | # Abnormal termination |
---|
824 | |
---|
825 | set logmesg "Abnormal program termination:" |
---|
826 | Log run failed [list $logmesg] |
---|
827 | set _job(mesg) "$logmesg\n\n$_job(stdout)" |
---|
828 | return 0; # Fail |
---|
829 | } |
---|
830 | if { $_uq(type) != "" } { |
---|
831 | CollectUQResults |
---|
832 | } |
---|
833 | |
---|
834 | # Step 5. Look in stdout for the name of the run file. |
---|
835 | set pattern {=RAPPTURE-RUN=>([^\n]+)} |
---|
836 | if {![regexp $pattern $_job(stdout) match fileName]} { |
---|
837 | set _job(mesg) "Can't find result file in output.\n" |
---|
838 | append _job(mesg) "Did you call Rappture::result in your simulator?" |
---|
839 | return 0; # Fail |
---|
840 | } |
---|
841 | set _job(runfile) $fileName |
---|
842 | set _job(success) 1 |
---|
843 | set _job(mesg) $_job(stdout) |
---|
844 | return 1; # Success |
---|
845 | } |
---|
846 | |
---|
847 | itcl::body Rappture::Task::LogSimulationUsage {} { |
---|
848 | array set times [Rappture::rusage measure] |
---|
849 | |
---|
850 | set toolId [$_xmlobj get tool.id] |
---|
851 | set toolVers [$_xmlobj get tool.version.application.revision] |
---|
852 | set simulation "simulation" |
---|
853 | if { $toolId ne "" && $toolVers ne "" } { |
---|
854 | set simulation "[pid]_${toolId}_r${toolVers}" |
---|
855 | } |
---|
856 | |
---|
857 | # Need to save job info? then invoke the callback |
---|
858 | if { [string length $jobstats] > 0} { |
---|
859 | lappend args "job" [incr jobnum] \ |
---|
860 | "event" $simulation \ |
---|
861 | "start" $times(start) \ |
---|
862 | "walltime" $times(walltime) \ |
---|
863 | "cputime" $times(cputime) \ |
---|
864 | "status" $_job(exitcode) |
---|
865 | uplevel #0 $jobstats $args |
---|
866 | } |
---|
867 | |
---|
868 | # |
---|
869 | # Scan through stderr channel and look for statements that |
---|
870 | # represent grid jobs that were executed. The statements look |
---|
871 | # like this: |
---|
872 | # |
---|
873 | # MiddlewareTime: job=1 event=simulation start=3.001094 ... |
---|
874 | # |
---|
875 | |
---|
876 | set subjobs 0 |
---|
877 | set pattern {(^|\n)MiddlewareTime:( +[a-z]+=[^ \n]+)+(\n|$)} |
---|
878 | while { [regexp -indices $pattern $_job(stderr) match] } { |
---|
879 | foreach {p0 p1} $match break |
---|
880 | if { [string index $_job(stderr) $p0] == "\n" } { |
---|
881 | incr p0 |
---|
882 | } |
---|
883 | array unset data |
---|
884 | array set data { |
---|
885 | job 1 |
---|
886 | event simulation |
---|
887 | start 0 |
---|
888 | walltime 0 |
---|
889 | cputime 0 |
---|
890 | status 0 |
---|
891 | } |
---|
892 | foreach arg [lrange [string range $_job(stderr) $p0 $p1] 1 end] { |
---|
893 | foreach {key val} [split $arg =] break |
---|
894 | set data($key) $val |
---|
895 | } |
---|
896 | set data(job) [expr { $jobnum + $data(job) }] |
---|
897 | set data(event) "subsimulation" |
---|
898 | set data(start) [expr { $times(start) + $data(start) }] |
---|
899 | |
---|
900 | set details "" |
---|
901 | foreach key {job event start walltime cputime status} { |
---|
902 | # Add required keys in a particular order |
---|
903 | lappend details $key $data($key) |
---|
904 | unset data($key) |
---|
905 | } |
---|
906 | foreach key [array names data] { |
---|
907 | # Add anything else that the client gave -- venue, etc. |
---|
908 | lappend details $key $data($key) |
---|
909 | } |
---|
910 | |
---|
911 | if {[string length $jobstats] > 0} { |
---|
912 | uplevel #0 $jobstats $details |
---|
913 | } |
---|
914 | |
---|
915 | incr subjobs |
---|
916 | |
---|
917 | # Done -- remove this statement |
---|
918 | set _job(stderr) [string replace $_job(stderr) $p0 $p1] |
---|
919 | } |
---|
920 | incr jobnum $subjobs |
---|
921 | |
---|
922 | # Add cputime info to run.xml file |
---|
923 | if { [catch { |
---|
924 | Rappture::library $_job(runfile) |
---|
925 | } xmlobj] != 0 } { |
---|
926 | error "Can't create rappture library: $xmlobj" |
---|
927 | } |
---|
928 | $xmlobj put output.walltime $times(walltime) |
---|
929 | $xmlobj put output.cputime $times(cputime) |
---|
930 | global env |
---|
931 | if {[info exists env(SESSION)]} { |
---|
932 | $xmlobj put output.session $env(SESSION) |
---|
933 | } |
---|
934 | set _job(xmlobj) $xmlobj |
---|
935 | } |
---|
936 | |
---|
937 | itcl::body Rappture::Task::LogSubmittedSimulationUsage {} { |
---|
938 | array set times [Rappture::rusage measure] |
---|
939 | |
---|
940 | set toolId [$_xmlobj get tool.id] |
---|
941 | set toolVers [$_xmlobj get tool.version.application.revision] |
---|
942 | set simulation "simulation" |
---|
943 | if { $toolId ne "" && $toolVers ne "" } { |
---|
944 | set simulation "[pid]_${toolId}_r${toolVers}" |
---|
945 | } |
---|
946 | |
---|
947 | # job info is not required because jobprotocol = submit |
---|
948 | # if { [string length $jobstats] > 0} { |
---|
949 | # lappend args \ |
---|
950 | # "job" [incr jobnum] \ |
---|
951 | # "event" $simulation \ |
---|
952 | # "start" $times(start) \ |
---|
953 | # "walltime" $times(walltime) \ |
---|
954 | # "cputime" $times(cputime) \ |
---|
955 | # "status" $_job(exitcode) |
---|
956 | # uplevel #0 $jobstats $args |
---|
957 | # } |
---|
958 | |
---|
959 | # [click] messages go here |
---|
960 | if { [string length $jobstats] > 0} { |
---|
961 | set recordJobstats 1 |
---|
962 | if { [info exists _resources(-cacheuser)] } { |
---|
963 | global env |
---|
964 | if { $env(USER) eq $_resources(-cacheuser) } { |
---|
965 | set recordJobstats 0 |
---|
966 | } |
---|
967 | } |
---|
968 | if { $recordJobstats } { |
---|
969 | lappend args "job" [incr jobnum] \ |
---|
970 | "event" "\[click\]" \ |
---|
971 | "start" $times(start) \ |
---|
972 | "walltime" 0 \ |
---|
973 | "cputime" 0 \ |
---|
974 | "status" 0 |
---|
975 | uplevel #0 $jobstats $args |
---|
976 | } |
---|
977 | } |
---|
978 | |
---|
979 | # |
---|
980 | # Scan through stderr channel and look for statements that |
---|
981 | # represent grid jobs that were executed. The statements look |
---|
982 | # like this: |
---|
983 | # |
---|
984 | # MiddlewareTime: job=1 event=simulation start=3.001094 ... |
---|
985 | # |
---|
986 | |
---|
987 | set subjobs 0 |
---|
988 | set pattern {(^|\n)MiddlewareTime:( +[a-z]+=[^ \n]+)+(\n|$)} |
---|
989 | while { [regexp -indices $pattern $_job(stderr) match] } { |
---|
990 | foreach {p0 p1} $match break |
---|
991 | if { [string index $_job(stderr) $p0] == "\n" } { |
---|
992 | incr p0 |
---|
993 | } |
---|
994 | array unset data |
---|
995 | array set data { |
---|
996 | job 1 |
---|
997 | event simulation |
---|
998 | start 0 |
---|
999 | walltime 0 |
---|
1000 | cputime 0 |
---|
1001 | status 0 |
---|
1002 | } |
---|
1003 | foreach arg [lrange [string range $_job(stderr) $p0 $p1] 1 end] { |
---|
1004 | foreach {key val} [split $arg =] break |
---|
1005 | set data($key) $val |
---|
1006 | } |
---|
1007 | set data(job) [expr { $jobnum + $data(job) }] |
---|
1008 | set data(event) "subsimulation" |
---|
1009 | set data(start) [expr { $times(start) + $data(start) }] |
---|
1010 | |
---|
1011 | # puts stderr "event subsimulation start = $data(start)" |
---|
1012 | |
---|
1013 | set details "" |
---|
1014 | foreach key {job event start walltime cputime status} { |
---|
1015 | # Add required keys in a particular order |
---|
1016 | lappend details $key $data($key) |
---|
1017 | unset data($key) |
---|
1018 | } |
---|
1019 | foreach key [array names data] { |
---|
1020 | # Add anything else that the client gave -- venue, etc. |
---|
1021 | lappend details $key $data($key) |
---|
1022 | } |
---|
1023 | |
---|
1024 | # if {[string length $jobstats] > 0} { |
---|
1025 | # uplevel #0 $jobstats $details |
---|
1026 | # } |
---|
1027 | |
---|
1028 | incr subjobs |
---|
1029 | |
---|
1030 | # Done -- remove this statement |
---|
1031 | set _job(stderr) [string replace $_job(stderr) $p0 $p1] |
---|
1032 | } |
---|
1033 | incr jobnum $subjobs |
---|
1034 | |
---|
1035 | # Add session info to run.xml file |
---|
1036 | if { [catch { |
---|
1037 | Rappture::library $_job(runfile) |
---|
1038 | } xmlobj] != 0 } { |
---|
1039 | error "Can't create rappture library: $xmlobj" |
---|
1040 | } |
---|
1041 | global env |
---|
1042 | if {[info exists env(SESSION)]} { |
---|
1043 | $xmlobj put output.session $env(SESSION) |
---|
1044 | } |
---|
1045 | set _job(xmlobj) $xmlobj |
---|
1046 | } |
---|
1047 | |
---|
1048 | itcl::body Rappture::Task::LogUQSimulationUsage {} { |
---|
1049 | array set times [Rappture::rusage measure] |
---|
1050 | |
---|
1051 | if { [string length $jobstats] > 0} { |
---|
1052 | lappend args "job" [incr jobnum] \ |
---|
1053 | "event" "\[click-uq\]" \ |
---|
1054 | "start" $times(start) \ |
---|
1055 | "walltime" 0 \ |
---|
1056 | "cputime" 0 \ |
---|
1057 | "status" 0 |
---|
1058 | uplevel #0 $jobstats $args |
---|
1059 | } |
---|
1060 | |
---|
1061 | # Add session info to run.xml file |
---|
1062 | if { [catch { Rappture::library $_job(runfile) } xmlobj] != 0 } { |
---|
1063 | error "Can't create rappture library: $xmlobj" |
---|
1064 | } |
---|
1065 | global env |
---|
1066 | if {[info exists env(SESSION)]} { |
---|
1067 | $xmlobj put output.session $env(SESSION) |
---|
1068 | } |
---|
1069 | set _job(xmlobj) $xmlobj |
---|
1070 | } |
---|
1071 | |
---|
1072 | itcl::body Rappture::Task::LogCachedSimulationUsage {} { |
---|
1073 | if { [catch { |
---|
1074 | Rappture::library $_job(runfile) |
---|
1075 | } xmlobj] != 0 } { |
---|
1076 | error "Can't create rappture library: $xmlobj" |
---|
1077 | } |
---|
1078 | set _job(xmlobj) $xmlobj |
---|
1079 | } |
---|
1080 | |
---|
1081 | |
---|
1082 | itcl::body Rappture::Task::CheckForCachedRunFile { driverFile } { |
---|
1083 | |
---|
1084 | # Read the driver file and collect its contents as the query. |
---|
1085 | set url http://$_resources(-cachehosts)/cache/request |
---|
1086 | set f [open $driverFile "r"] |
---|
1087 | set query [read $f] |
---|
1088 | close $f |
---|
1089 | |
---|
1090 | # Make the query |
---|
1091 | if { [catch { |
---|
1092 | http::geturl $url -query $query -timeout 6000 -binary yes |
---|
1093 | } token] != 0 } { |
---|
1094 | puts stderr "error performing cache query: driverFile=$driverFile url=$url token=$token" |
---|
1095 | return 0 |
---|
1096 | } |
---|
1097 | |
---|
1098 | # puts stderr "ncode = [http::ncode $token]" |
---|
1099 | # puts stderr "code = [::http::code $token]" |
---|
1100 | # puts stderr "status = [::http::status $token]" |
---|
1101 | # puts stderr "meta = [::http::meta $token]" |
---|
1102 | |
---|
1103 | set squid "" |
---|
1104 | foreach {key value} [::http::meta $token] { |
---|
1105 | set headers([string tolower $key]) $value |
---|
1106 | if { [string tolower $key] == "etag" } { |
---|
1107 | set squid $value |
---|
1108 | } |
---|
1109 | } |
---|
1110 | # puts stderr "SQUID = $headers(etag)" |
---|
1111 | # puts stderr "SQUID = $squid" |
---|
1112 | if { [resources -jobprotocol] == "submit" } { |
---|
1113 | if { $squid != "" } { |
---|
1114 | # If the code is 200, we'll assume it's a cache hit. |
---|
1115 | if { [http::ncode $token] == 200} { |
---|
1116 | if { [catch {exec submit --cacheHit $squid} result] != 0 } { |
---|
1117 | puts stderr "submit --cacheHit $squid failed: $result" |
---|
1118 | } |
---|
1119 | # puts stderr "submit --cacheHit $squid" |
---|
1120 | } else { |
---|
1121 | if { [catch {exec submit --cacheMiss $squid} result] != 0 } { |
---|
1122 | puts stderr "submit --cacheMiss $squid failed: $result" |
---|
1123 | } |
---|
1124 | # puts stderr "submit --cacheMiss $squid" |
---|
1125 | } |
---|
1126 | } else { |
---|
1127 | puts stderr "cache squid could not be determined." |
---|
1128 | } |
---|
1129 | } |
---|
1130 | |
---|
1131 | # If the code isn't 200, we'll assume it's a cache miss. |
---|
1132 | if { [http::ncode $token] != 200} { |
---|
1133 | return 0 |
---|
1134 | } |
---|
1135 | # Get contents of the run file. |
---|
1136 | set contents [http::data $token] |
---|
1137 | if { $contents == "" } { |
---|
1138 | return 0 |
---|
1139 | } |
---|
1140 | |
---|
1141 | # Create a new run.xml file and write the results into it. |
---|
1142 | set secs [clock seconds] |
---|
1143 | set millisecs [expr [clock clicks -milliseconds] % 1000] |
---|
1144 | set timestamp [format %d%03d%03d $secs $millisecs 0] |
---|
1145 | |
---|
1146 | global rapptureInfo |
---|
1147 | set fileName [file join $rapptureInfo(cwd) "run${timestamp}.xml"] |
---|
1148 | set f [open $fileName "w"] |
---|
1149 | puts $f $contents |
---|
1150 | close $f |
---|
1151 | set _job(runfile) $fileName |
---|
1152 | set _job(success) 1 |
---|
1153 | set _job(stderr) "Loading cached results\n" |
---|
1154 | OnOutput "Loading cached results\n" |
---|
1155 | update |
---|
1156 | return 1 |
---|
1157 | } |
---|
1158 | |
---|
1159 | itcl::body Rappture::Task::GetUQErrors {} { |
---|
1160 | set contents {} |
---|
1161 | if { [file exists "uq_debug.err"] } { |
---|
1162 | set f [open "uq_debug.err" r] |
---|
1163 | set contents [read $f] |
---|
1164 | close $f |
---|
1165 | } |
---|
1166 | return $contents |
---|
1167 | } |
---|
1168 | |
---|
1169 | # UQ. Collect data from all jobs and put it in one xml run file. |
---|
1170 | itcl::body Rappture::Task::CollectUQResults {} { |
---|
1171 | file delete -force -- "run_uq.xml" |
---|
1172 | set hdfFile puq_[pid].hdf5 |
---|
1173 | if { [catch { |
---|
1174 | exec puq.sh analyze $hdfFile |
---|
1175 | } results] != 0 } { |
---|
1176 | error "UQ analysis failed: $results\n[GetUQErrors]" |
---|
1177 | } else { |
---|
1178 | set _job(stdout) $results |
---|
1179 | } |
---|
1180 | } |
---|