source: trunk/gui/scripts/tool.tcl @ 158

Last change on this file since 158 was 158, checked in by mmc, 19 years ago
  • Fixed installation so that this "gui" part can be installed with standard autoconf techniques: configure, make all, make install The "gui" library is loaded via "package require RapptureGUI"
  • Added C code for Rappture::rlimit, to support limits on CPU time and file sizes. Default limits are 15 mins of CPU and 1MB for each file. These can be overridden in tool.xml by using <tool><limits><cputime> and <tool><limits><filesize>.
  • Added C code for Rappture::rusage, so we can collect resource usage for all child processes. Each Simulation now reports a line of usage to stderr as follows:

MiddlewareTime?: job=# event=simulation start=xxx cputime=xxx ...

  • Fixed Rappture::exec so that it reports proper error messages when rlimits are execeeded.
File size: 6.5 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: tool - represents an entire tool
3#
4#  This object represents an entire tool defined by Rappture.
5#  Each tool resides in an installation directory with other tool
6#  resources (libraries, examples, etc.).  Each tool is defined by
7#  its inputs and outputs, which are tied to various widgets in the
8#  GUI.  Each tool tracks the inputs, knows when they're changed,
9#  and knows how to run itself to produce new results.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005  Purdue Research Foundation
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require BLT
18
19itcl::class Rappture::Tool {
20    inherit Rappture::ControlOwner
21
22    constructor {xmlobj installdir args} {
23        Rappture::ControlOwner::constructor ""
24    } { # defined below }
25
26    public method installdir {} { return $_installdir }
27
28    public method run {args}
29    public method abort {}
30
31    protected method _output {data}
32
33    private variable _installdir ""  ;# installation directory for this tool
34    private variable _outputcb ""    ;# callback for tool output
35    private common job               ;# array var used for blt::bgexec jobs
36    private common jobnum 0          ;# counter for unique job number
37}
38                                                                               
39# ----------------------------------------------------------------------
40# CONSTRUCTOR
41# ----------------------------------------------------------------------
42itcl::body Rappture::Tool::constructor {xmlobj installdir args} {
43    if {![Rappture::library isvalid $xmlobj]} {
44        error "bad value \"$xmlobj\": should be Rappture::Library"
45    }
46    set _xmlobj $xmlobj
47
48    if {![file exists $installdir]} {
49        error "directory \"$installdir\" doesn't exist"
50    }
51    set _installdir $installdir
52
53    eval configure $args
54}
55
56# ----------------------------------------------------------------------
57# USAGE: run ?<path1> <value1> <path2> <value2> ...? ?-output <callbk>?
58#
59# This method causes the tool to run.  All widgets are synchronized
60# to the current XML representation, and a "driver.xml" file is
61# created as the input for the run.  That file is fed to the tool
62# according to the <tool><command> string, and the job is executed.
63#
64# Any "<path> <value>" arguments are used to override the current
65# settings from the GUI.  This is useful, for example, when filling
66# in missing simulation results from the analyzer.
67#
68# If the -output argument is included, then the next arg is a
69# callback command for output messages.  Any output that comes in
70# while the tool is running is sent back to the caller, so the user
71# can see progress running the tool.
72#
73# Returns a list of the form {status result}, where status is an
74# integer status code (0=success) and result is the output from the
75# simulator.  Successful output is something like {0 run1293921.xml},
76# where 0=success and run1293921.xml is the name of the file containing
77# results.
78# ----------------------------------------------------------------------
79itcl::body Rappture::Tool::run {args} {
80    global errorInfo
81
82    # sync all widgets to the XML tree
83    sync
84
85    # if there are any args, use them to override parameters
86    set _outputcb ""
87    foreach {path val} $args {
88        if {$path == "-output"} {
89            set _outputcb $val
90        } else {
91            $_xmlobj put $path.current $val
92        }
93    }
94
95    foreach item {control output error} { set job($item) "" }
96
97    # write out the driver.xml file for the tool
98    set file "driver[pid].xml"
99    set status [catch {
100        set fid [open $file w]
101        puts $fid "<?xml version=\"1.0\"?>"
102        puts $fid [$_xmlobj xml]
103        close $fid
104    } result]
105
106    # set limits for cpu time and file size
107    set limit [$_xmlobj get tool.limits.cputime]
108    if {"" == $limit || [catch {Rappture::rlimit set cputime $limit}]} {
109        Rappture::rlimit set cputime 900  ;# 15 mins by default
110    }
111
112    set limit [$_xmlobj get tool.limits.filesize]
113    if {"" == $limit || [catch {Rappture::rlimit set filesize $limit}]} {
114        Rappture::rlimit set filesize 1000000  ;# 1MB by default
115    }
116
117    # execute the tool using the path from the tool description
118    if {$status == 0} {
119        set cmd [$_xmlobj get tool.command]
120        regsub -all @tool $cmd $_installdir cmd
121        regsub -all @driver $cmd $file cmd
122
123        # starting job...
124        Rappture::rusage mark
125
126        set status [catch {eval blt::bgexec \
127            ::Rappture::Tool::job(control) \
128            -keepnewline yes \
129            -onoutput [list [itcl::code $this _output]] \
130            -output ::Rappture::Tool::job(output) \
131            -error ::Rappture::Tool::job(error) $cmd} result]
132
133        # ...job is finished
134        array set times [Rappture::rusage measure]
135        puts stderr "MiddlewareTime: job=[incr jobnum] event=simulation start=$times(start) walltime=$times(walltime) cputime=$times(cputime) status=$status"
136
137    } else {
138        set job(error) "$result\n$errorInfo"
139    }
140    if {$status == 0} {
141        file delete -force -- $file
142    }
143
144    # see if the job was aborted
145    if {[regexp {^KILLED} $job(control)]} {
146        return [list 0 "ABORT"]
147    }
148
149    #
150    # If successful, return the output, which should include
151    # a reference to the run.xml file containing results.
152    #
153    if {$status == 0} {
154        set file [string trim $job(output)]
155        return [list $status $file]
156    } elseif {"" != $job(output) || "" != $job(error)} {
157        return [list $status [string trim "$job(output)\n$job(error)"]]
158    }
159    return [list $status $result]
160}
161
162# ----------------------------------------------------------------------
163# USAGE: abort
164#
165# Clients use this during a "run" to abort the current job.
166# Kills the job and forces the "run" method to return.
167# ----------------------------------------------------------------------
168itcl::body Rappture::Tool::abort {} {
169    set job(control) "abort"
170}
171
172# ----------------------------------------------------------------------
173# USAGE: _output <data>
174#
175# Used internally to send each bit of output <data> coming from the
176# tool onto the caller, so the user can see progress.
177# ----------------------------------------------------------------------
178itcl::body Rappture::Tool::_output {data} {
179    if {[string length $_outputcb] > 0} {
180        uplevel #0 [list $_outputcb $data]
181    }
182}
Note: See TracBrowser for help on using the repository browser.