source: trunk/lang/tcl/src/RpRusage.c @ 1264

Last change on this file since 1264 was 1018, checked in by gah, 16 years ago

Massive changes: New directory/file layout

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