source: trunk/gui/src/RpRusage.c @ 503

Last change on this file since 503 was 503, checked in by nkissebe, 18 years ago

Converted to Tcl Extension Architecture (TEA) v3.5 for base Windows support. Added Windows ports of getrlimit, getrusage, gettimeofday, setrlimit functions.

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