source: trunk/gui/src/RpRusage.c @ 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: 8.0 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  Rappture::rusage
4 *
5 *  This is an interface to the system getrusage() routine.  It allows
6 *  you to query resource used by child executables.  We use this in
7 *  Rappture to track the usage during each click of the "Simulate"
8 *  button.
9 * ======================================================================
10 *  AUTHOR:  Michael McLennan, Purdue University
11 *  Copyright (c) 2004-2006  Purdue Research Foundation
12 *
13 *  See the file "license.terms" for information on usage and
14 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15 * ======================================================================
16 */
17#include <tcl.h>
18#include <sys/time.h>
19#include <sys/resource.h>
20
21#include "bltInt.h"
22
23/*
24 * Store rusage info in this data structure:
25 */
26typedef struct RpRusageStats {
27    struct timeval times;
28    struct rusage resources;
29} RpRusageStats;
30
31static RpRusageStats RpRusage_Start;      /* time at start of program */
32static RpRusageStats RpRusage_MarkStats;  /* stats from last "mark" */
33
34
35static int RpRusageCmd _ANSI_ARGS_((ClientData cdata,
36    Tcl_Interp *interp, int argc, CONST84 char *argv[]));
37static int RpRusageMarkOp _ANSI_ARGS_((ClientData cdata,
38    Tcl_Interp *interp, int argc, char *argv[]));
39static int RpRusageMeasureOp _ANSI_ARGS_((ClientData cdata,
40    Tcl_Interp *interp, int argc, char *argv[]));
41static int RpRusageCapture _ANSI_ARGS_((Tcl_Interp *interp,
42    RpRusageStats *rptr));
43static double RpRusageTimeDiff _ANSI_ARGS_((struct timeval *currptr,
44    struct timeval *prevptr));
45
46/*
47 * rusage subcommands:
48 */
49static Blt_OpSpec rusageOps[] = {
50    {"mark", 2, (Blt_Op)RpRusageMarkOp, 2, 2, "",},
51    {"measure", 2, (Blt_Op)RpRusageMeasureOp, 2, 2, "",},
52};
53static int nRusageOps = sizeof(rusageOps) / sizeof(Blt_OpSpec);
54
55/*
56 * ------------------------------------------------------------------------
57 *  RpRusage_Init()
58 *
59 *  Called in RapptureGUI_Init() to initialize the commands defined
60 *  in this file.
61 * ------------------------------------------------------------------------
62 */
63int
64RpRusage_Init(interp)
65    Tcl_Interp *interp;  /* interpreter being initialized */
66{
67    Tcl_CreateCommand(interp, "::Rappture::rusage",
68        RpRusageCmd, (ClientData)NULL, (Tcl_CmdDeleteProc*)NULL);
69
70    /* set an initial mark automatically */
71    if (RpRusageMarkOp(NULL, interp, 0, (char**)NULL) != TCL_OK) {
72        return TCL_ERROR;
73    }
74
75    /* capture the starting time for this program */
76    memcpy(&RpRusage_Start, &RpRusage_MarkStats, sizeof(RpRusageStats));
77
78    return TCL_OK;
79}
80
81/*
82 * ------------------------------------------------------------------------
83 *  RpRusageCmd()
84 *
85 *  Invoked whenever someone uses the "rusage" command to get/set
86 *  limits for child processes.  Handles the following syntax:
87 *
88 *      rusage mark
89 *      rusage measure
90 *
91 *  Returns TCL_OK on success, and TCL_ERROR (along with an error
92 *  message in the interpreter) if anything goes wrong.
93 * ------------------------------------------------------------------------
94 */
95static int
96RpRusageCmd(cdata, interp, argc, argv)
97    ClientData cdata;         /* not used */
98    Tcl_Interp *interp;       /* interpreter handling this request */
99    int argc;                 /* number of command line args */
100    CONST84 char *argv[];     /* strings for command line args */
101{
102    Blt_Op proc;
103
104    proc = Blt_GetOp(interp, nRusageOps, rusageOps, BLT_OP_ARG1,
105        argc, (char**)argv, 0);
106
107    if (proc == NULL) {
108        return TCL_ERROR;
109    }
110    return (*proc)(cdata, interp, argc, argv);
111}
112
113/*
114 * ------------------------------------------------------------------------
115 *  RpRusageMarkOp()
116 *
117 *  Invoked whenever someone uses the "rusage mark" command to mark
118 *  the start of an execution.  Handles the following syntax:
119 *
120 *      rusage mark
121 *
122 *  Returns TCL_OK on success, and TCL_ERROR (along with an error
123 *  message in the interpreter) if anything goes wrong.
124 * ------------------------------------------------------------------------
125 */
126static int
127RpRusageMarkOp(cdata, interp, argc, argv)
128    ClientData cdata;         /* not used */
129    Tcl_Interp *interp;       /* interpreter handling this request */
130    int argc;                 /* number of command line args */
131    char *argv[];             /* strings for command line args */
132{
133    return RpRusageCapture(interp, &RpRusage_MarkStats);
134}
135
136/*
137 * ------------------------------------------------------------------------
138 *  RpRusageMeasureOp()
139 *
140 *  Invoked whenever someone uses the "rusage measure" command to
141 *  measure resource usage since the last "mark" operation.  Handles
142 *  the following syntax:
143 *
144 *      rusage measure
145 *
146 *  Returns TCL_OK on success, and TCL_ERROR (along with an error
147 *  message in the interpreter) if anything goes wrong.
148 * ------------------------------------------------------------------------
149 */
150static int
151RpRusageMeasureOp(cdata, interp, argc, argv)
152    ClientData cdata;         /* not used */
153    Tcl_Interp *interp;       /* interpreter handling this request */
154    int argc;                 /* number of command line args */
155    char *argv[];             /* strings for command line args */
156{
157    double tval;
158    RpRusageStats curstats;
159    char buffer[TCL_DOUBLE_SPACE];
160
161    if (RpRusageCapture(interp, &curstats) != TCL_OK) {
162        return TCL_ERROR;
163    }
164
165    /*
166     * Compute: START TIME
167     */
168    Tcl_AppendElement(interp, "start");
169    tval = RpRusageTimeDiff(&RpRusage_MarkStats.times, &RpRusage_Start.times);
170    Tcl_PrintDouble(interp, tval, buffer);
171    Tcl_AppendElement(interp, buffer);
172
173    /*
174     * Compute: WALL TIME
175     */
176    Tcl_AppendElement(interp, "walltime");
177    tval = RpRusageTimeDiff(&curstats.times, &RpRusage_MarkStats.times);
178    Tcl_PrintDouble(interp, tval, buffer);
179    Tcl_AppendElement(interp, buffer);
180
181    /*
182     * Compute: CPU TIME = user time + system time
183     */
184    Tcl_AppendElement(interp, "cputime");
185    tval = RpRusageTimeDiff(&curstats.resources.ru_utime,
186             &RpRusage_MarkStats.resources.ru_utime)
187         + RpRusageTimeDiff(&curstats.resources.ru_stime,
188             &RpRusage_MarkStats.resources.ru_stime);
189    Tcl_PrintDouble(interp, tval, buffer);
190    Tcl_AppendElement(interp, buffer);
191
192    return TCL_OK;
193}
194
195/*
196 * ------------------------------------------------------------------------
197 *  RpRusageCapture()
198 *
199 *  Used internally to capture a snapshot of current time and resource
200 *  usage.  Stores the stats in the given data structure.
201 *
202 *  Returns TCL_OK on success, and TCL_ERROR (along with an error
203 *  message in the interpreter) if anything goes wrong.
204 * ------------------------------------------------------------------------
205 */
206static int
207RpRusageCapture(interp, rptr)
208    Tcl_Interp *interp;       /* interpreter handling this request */
209    RpRusageStats *rptr;      /* returns: snapshot of stats */
210{
211    int status;
212
213    status = getrusage(RUSAGE_CHILDREN, &rptr->resources);
214    if (status != 0) {
215        Tcl_AppendResult(interp, "unexpected error from getrusage()",
216            (char*)NULL);
217        return TCL_ERROR;
218    }
219
220    status = gettimeofday(&rptr->times, (struct timezone*)NULL);
221    if (status != 0) {
222        Tcl_AppendResult(interp, "unexpected error from gettimeofday()",
223            (char*)NULL);
224        return TCL_ERROR;
225    }
226
227    return TCL_OK;
228}
229
230/*
231 * ------------------------------------------------------------------------
232 *  RpRusageTimeDiff()
233 *
234 *  Used internally to compute the difference between two timeval
235 *  structures.  Returns a double precision value representing the
236 *  time difference.
237 * ------------------------------------------------------------------------
238 */
239static double
240RpRusageTimeDiff(currptr, prevptr)
241    struct timeval *currptr;  /* current time */
242    struct timeval *prevptr;  /*  - previous time */
243{
244    double tval;
245
246    if (prevptr) {
247        tval = (currptr->tv_sec - prevptr->tv_sec)
248                 + 1.0e-6*(currptr->tv_usec - prevptr->tv_usec);
249    } else {
250        tval = currptr->tv_sec + 1.0e-6*currptr->tv_usec;
251    }
252    return tval;
253}
Note: See TracBrowser for help on using the repository browser.