Added pause_time metric.
[dyninst.git] / paradynd / src / context.C
1 /*
2  *  Copyright 1993 Jeff Hollingsworth.  All rights reserved.
3  *
4  */
5
6 #ifndef lint
7 static char Copyright[] = "@(#) Copyright (c) 1993 Jeff Hollingsowrth\
8     All rights reserved.";
9
10 static char rcsid[] = "@(#) $Header: /home/jaw/CVSROOT_20081103/CVSROOT/core/paradynd/src/context.C,v 1.6 1994/04/11 23:25:21 hollings Exp $";
11 #endif
12
13 /*
14  * context.c - manage a performance context.
15  *
16  * $Log: context.C,v $
17  * Revision 1.6  1994/04/11 23:25:21  hollings
18  * Added pause_time metric.
19  *
20  * Revision 1.5  1994/04/09  18:34:51  hollings
21  * Changed {pause,continue}Application to {pause,continue}AllProceses, and
22  * made the RPC interfaces use these.  This makes the computation of pause
23  * Time correct.
24  *
25  * Revision 1.4  1994/03/31  01:47:54  markc
26  * Extended parameters for addProcess, which default to NULL and 0.
27  *
28  * Revision 1.3  1994/03/22  21:03:12  hollings
29  * Made it possible to add new processes (& paradynd's) via addExecutable.
30  *
31  * Revision 1.2  1994/03/20  01:53:03  markc
32  * Added a buffer to each process structure to allow for multiple writers on the
33  * traceStream.  Replaced old inst-pvm.C.  Changed addProcess to return type
34  * int.
35  *
36  * Revision 1.1  1994/01/27  20:31:15  hollings
37  * Iinital version of paradynd speaking dynRPC igend protocol.
38  *
39  * Revision 1.11  1993/12/13  19:52:40  hollings
40  * added applicationDefined
41  *
42  * Revision 1.10  1993/10/19  15:27:54  hollings
43  * AST based mini-tramp code generator.
44  *
45  * Revision 1.9  1993/10/01  21:29:41  hollings
46  * Added resource discovery and filters.
47  *
48  * Revision 1.8  1993/08/16  16:24:08  hollings
49  * added prototype for ptrace.
50  *
51  * Revision 1.7  1993/08/11  01:45:37  hollings
52  * added support for UNIX fork.
53  *
54  * Revision 1.6  1993/07/13  18:26:13  hollings
55  * new include file syntax.
56  *
57  * Revision 1.5  1993/06/28  23:13:18  hollings
58  * fixed process stopping.
59  *
60  * Revision 1.4  1993/06/24  16:18:06  hollings
61  * global fixes.
62  *
63  * Revision 1.3  1993/06/22  19:00:01  hollings
64  * global inst state.
65  *
66  * Revision 1.2  1993/06/08  20:14:34  hollings
67  * state prior to bc net ptrace replacement.
68  *
69  * Revision 1.1  1993/03/19  22:45:18  hollings
70  * Initial revision
71  *
72  *
73  */
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <assert.h>
77 #include <string.h>
78 #include <sys/time.h>
79 #include <sys/ptrace.h>
80 #include <sys/signal.h>
81
82 #include "symtab.h"
83 #include "process.h"
84 #include "rtinst/h/rtinst.h"
85 #include "rtinst/h/trace.h"
86 #include "dyninst.h"
87 #include "dyninstP.h"
88 #include "inst.h"
89 #include "instP.h"
90 #include "ast.h"
91 #include "util.h"
92
93 #define MILLION 1000000
94
95 // <sts/ptrace.h> should really define this. 
96 extern "C" {
97
98 int ptrace(enum ptracereq request, 
99                       int pid, 
100                       char *addr, 
101                       int data, 
102                       char *addr2);
103 }
104
105 /*
106  * find out if we have an application defined.
107  */
108 Boolean applicationDefined()
109 {
110     if (processList.count()) {
111         return(True);
112     } else {
113         return(False);
114     }
115 }
116
117 static AstNode tagArg(Param, (void *) 2);
118
119 instMaping initialRequests[] = {
120     { "cmmd_debug", "DYNINSTnodeCreate", FUNC_ENTRY },
121     { "cmmd_debug", "DYNINSTparallelInit", FUNC_EXIT },
122     { "cmmd_debug", "DYNINSTbreakPoint", FUNC_EXIT },
123     { "main", "DYNINSTsampleValues", FUNC_EXIT },
124 #ifdef notdef
125     { "fork", "DYNINSTfork", FUNC_EXIT|FUNC_FULL_ARGS },
126 #endif
127     { "exit", "DYNINSTsampleValues", FUNC_ENTRY },
128     { "exit", "DYNINSTbreakPoint", FUNC_ENTRY },
129     { "main", "DYNINSTinit", FUNC_ENTRY },
130     { "DYNINSTsampleValues", "DYNINSTreportNewTags", FUNC_ENTRY },
131     { "CMMD_send", "DYNINSTrecordTag", FUNC_ENTRY|FUNC_ARG, &tagArg },
132     { "CMMD_receive", "DYNINSTrecordTag", FUNC_ENTRY|FUNC_ARG, &tagArg },
133     { "CMMP_receive_block", "DYNINSTrecordTag", FUNC_ENTRY|FUNC_ARG, &tagArg },
134     { "CMMP_send_block", "DYNINSTrecordTag", FUNC_ENTRY|FUNC_ARG, &tagArg },
135     { "CMMP_send_async", "DYNINSTrecordTag", FUNC_ENTRY|FUNC_ARG, &tagArg },
136     { "CMMP_receive_async", "DYNINSTrecordTag", FUNC_ENTRY|FUNC_ARG, &tagArg },
137     { NULL, NULL, 0, NULL },
138 };
139
140 void forkProcess(traceHeader *hr, traceFork *fr)
141 {
142     int val;
143     process *ret;
144     char name[80];
145     process *parent;
146     struct executableRec *newExec;
147
148     parent = findProcess(fr->ppid);
149     assert(parent);
150
151     /* attach to the process */
152     val = ptrace(PTRACE_ATTACH, fr->pid, 0, 0, 0);
153     if (val != 0) {
154         perror("nptrace");
155         return;
156     }
157
158     sprintf(name, "%s[%d]", parent->symbols->name, fr->pid);
159     ret = allocateProcess(fr->pid, name);
160     ret->symbols = parseImage(parent->symbols->file, 0);
161     ret->traceLink = parent->traceLink;
162     ret->parent = parent;
163
164     copyInferriorHeap(parent, ret);
165     // installDefaultInst(ret, initialRequests);
166
167     newExec = (struct executableRec *) calloc(sizeof(struct executableRec), 1);
168
169     newExec->name = name;
170     newExec->type = selfTermination;
171     newExec->state = neonatal;
172     newExec->proc = ret;
173 }
174
175 int addProcess(int argc, char *argv[], int nenv, char *envp[])
176 {
177     int i;
178     struct executableRec *newExec;
179
180     newExec = (struct executableRec *) calloc(sizeof(struct executableRec), 1);
181
182     newExec->argc = argc;
183     newExec->argv = (char **) calloc(sizeof(char *), argc+1);
184     for (i=0; i < argc; i++) {
185         newExec->argv[i] = strdup(argv[i]);
186     }
187
188     newExec->name = strdup(argv[0]);
189     newExec->type = selfTermination;
190     newExec->state = neonatal;
191     
192     newExec->proc = createProcess(newExec->argv[0], newExec->argv, nenv, envp);
193     if (newExec->proc) {
194         installDefaultInst(newExec->proc, initialRequests);
195         return(newExec->proc->pid);
196     } else {
197         free(newExec);
198         return(-1);
199     }
200 }
201
202 Boolean detachProcess(int pid, Boolean paused)
203 {
204     struct List<process *> curr;
205
206     for (curr = processList; *curr; curr++) {
207         if ((*curr)->pid == pid) {
208             PCptrace(PTRACE_DETACH, *curr, (int*) 1, SIGCONT, NULL);
209             if (paused) {
210                 (void) kill((*curr)->pid, SIGSTOP);
211                 fprintf(stderr, "deatching process %d leaving it paused\n", 
212                     (*curr)->pid);
213             }
214         }
215     }
216     return(False);
217 }
218
219 Boolean addDataSource(char *name, char *machine,
220     char *login, char *command, int argc, char *argv[])
221 {
222     abort();
223     return(False);
224 }
225
226 Boolean startApplication()
227 {
228     continueAllProcesses();
229     return(False);
230 }
231
232 timeStamp endPause;
233 timeStamp startPause;
234 Boolean applicationPaused;
235 extern Boolean firstSampleReceived;
236
237 // total processor time the application has been paused.
238 // so for a multi-processor system this should be processor * time.
239 timeStamp elapsedPauseTime;
240
241 Boolean markApplicationPaused()
242 {
243     struct timeval tv;
244
245     if (applicationPaused) return(False);
246     applicationPaused = True;
247
248     // get the time when we paused it.
249
250     gettimeofday(&tv, NULL);
251     startPause = tv.tv_sec;
252     startPause *= MILLION;
253     startPause += tv.tv_usec;
254     printf("paused at %f\n", startPause / 1000000.0);
255     
256     return(True);
257 }
258
259 Boolean isApplicationPaused()
260 {
261     return(applicationPaused);
262 }
263
264 Boolean continueAllProcesses()
265 {
266     sampleValue val;
267     struct timeval tv;
268     struct List<process *> curr;
269     extern void computePauseTimeMetric(time64, time64, sampleValue);
270
271     for (curr = processList; *curr; curr++) {
272         continueProcess(*curr);
273     }
274
275     if (!applicationPaused) return(False);
276     applicationPaused = False;
277
278     gettimeofday(&tv, NULL);
279     endPause = tv.tv_sec;
280     endPause *= MILLION;
281     endPause += tv.tv_usec;
282
283     if (!firstSampleReceived) {
284         return(False);
285     }
286
287     elapsedPauseTime += (endPause - startPause);
288     printf("continued at %f\n", endPause / 1000000.0);
289
290     return(False);
291 }
292
293 Boolean pauseAllProcesses()
294 {
295     Boolean changed;
296     struct List<process *> curr;
297
298     changed = markApplicationPaused();
299     for (curr = processList; *curr; curr++) {
300         pauseProcess(*curr);
301     }
302     flushPtrace();
303     return(changed);
304 }