[158] | 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> |
---|
[1018] | 18 | #include <string.h> |
---|
[503] | 19 | #ifndef WIN32 |
---|
[158] | 20 | #include <sys/time.h> |
---|
| 21 | #include <sys/resource.h> |
---|
[503] | 22 | #else |
---|
| 23 | #include "RpWinResource.h" |
---|
| 24 | #endif |
---|
[158] | 25 | |
---|
[1018] | 26 | #include "RpOp.h" |
---|
[158] | 27 | |
---|
| 28 | /* |
---|
| 29 | * Store rusage info in this data structure: |
---|
| 30 | */ |
---|
| 31 | typedef struct RpRusageStats { |
---|
| 32 | struct timeval times; |
---|
| 33 | struct rusage resources; |
---|
| 34 | } RpRusageStats; |
---|
| 35 | |
---|
| 36 | static RpRusageStats RpRusage_Start; /* time at start of program */ |
---|
| 37 | static RpRusageStats RpRusage_MarkStats; /* stats from last "mark" */ |
---|
| 38 | |
---|
| 39 | |
---|
[1018] | 40 | static Tcl_ObjCmdProc RpRusageCmd; |
---|
| 41 | static Tcl_ObjCmdProc RpRusageMarkOp; |
---|
| 42 | static Tcl_ObjCmdProc RpRusageMeasureOp; |
---|
| 43 | |
---|
[158] | 44 | static int RpRusageCapture _ANSI_ARGS_((Tcl_Interp *interp, |
---|
| 45 | RpRusageStats *rptr)); |
---|
| 46 | static double RpRusageTimeDiff _ANSI_ARGS_((struct timeval *currptr, |
---|
| 47 | struct timeval *prevptr)); |
---|
| 48 | |
---|
| 49 | /* |
---|
| 50 | * rusage subcommands: |
---|
| 51 | */ |
---|
[1018] | 52 | static Rp_OpSpec rusageOps[] = { |
---|
| 53 | {"mark", 2, RpRusageMarkOp, 2, 2, "",}, |
---|
| 54 | {"measure", 2, RpRusageMeasureOp, 2, 2, "",}, |
---|
[158] | 55 | }; |
---|
[1018] | 56 | static int nRusageOps = sizeof(rusageOps) / sizeof(Rp_OpSpec); |
---|
[158] | 57 | |
---|
| 58 | /* |
---|
| 59 | * ------------------------------------------------------------------------ |
---|
| 60 | * RpRusage_Init() |
---|
| 61 | * |
---|
[1018] | 62 | * Called in Rappture_Init() to initialize the commands defined |
---|
[158] | 63 | * in this file. |
---|
| 64 | * ------------------------------------------------------------------------ |
---|
| 65 | */ |
---|
| 66 | int |
---|
| 67 | RpRusage_Init(interp) |
---|
| 68 | Tcl_Interp *interp; /* interpreter being initialized */ |
---|
| 69 | { |
---|
[1018] | 70 | Tcl_CreateObjCommand(interp, "::Rappture::rusage", RpRusageCmd, |
---|
| 71 | NULL, NULL); |
---|
[158] | 72 | |
---|
| 73 | /* set an initial mark automatically */ |
---|
[1018] | 74 | if (RpRusageMarkOp(NULL, interp, 0, (Tcl_Obj**)NULL) != TCL_OK) { |
---|
[158] | 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 | */ |
---|
| 98 | static int |
---|
[1018] | 99 | RpRusageCmd(cdata, interp, objc, objv) |
---|
[158] | 100 | ClientData cdata; /* not used */ |
---|
| 101 | Tcl_Interp *interp; /* interpreter handling this request */ |
---|
[1018] | 102 | int objc; /* number of command line args */ |
---|
| 103 | Tcl_Obj *const *objv; /* strings for command line args */ |
---|
[158] | 104 | { |
---|
[1018] | 105 | Tcl_ObjCmdProc *proc; |
---|
[158] | 106 | |
---|
[1018] | 107 | proc = Rp_GetOpFromObj(interp, nRusageOps, rusageOps, RP_OP_ARG1, |
---|
| 108 | objc, objv, 0); |
---|
[158] | 109 | |
---|
| 110 | if (proc == NULL) { |
---|
| 111 | return TCL_ERROR; |
---|
| 112 | } |
---|
[1018] | 113 | return (*proc)(cdata, interp, objc, objv); |
---|
[158] | 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 | */ |
---|
| 129 | static int |
---|
[1018] | 130 | RpRusageMarkOp(cdata, interp, objc, objv) |
---|
[158] | 131 | ClientData cdata; /* not used */ |
---|
| 132 | Tcl_Interp *interp; /* interpreter handling this request */ |
---|
[1018] | 133 | int objc; /* number of command line args */ |
---|
| 134 | Tcl_Obj *const *objv; /* strings for command line args */ |
---|
[158] | 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 | */ |
---|
| 153 | static int |
---|
[1018] | 154 | RpRusageMeasureOp(cdata, interp, objc, objv) |
---|
[158] | 155 | ClientData cdata; /* not used */ |
---|
| 156 | Tcl_Interp *interp; /* interpreter handling this request */ |
---|
[1018] | 157 | int objc; /* number of command line args */ |
---|
| 158 | Tcl_Obj *const *objv; /* strings for command line args */ |
---|
[158] | 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 | */ |
---|
| 209 | static int |
---|
| 210 | RpRusageCapture(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 | */ |
---|
| 242 | static double |
---|
| 243 | RpRusageTimeDiff(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 | } |
---|
[503] | 257 | |
---|