remove compiler warning; add ability to update aggregation intervals;
[dyninst.git] / paradynd / src / dynrpc.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /* $Id: dynrpc.C,v 1.84 2001/08/23 14:44:04 schendel Exp $ */
43
44 #include "dyninstAPI/src/symtab.h"
45 #include "dyninstAPI/src/process.h"
46 #include "dyninstAPI/src/inst.h"
47 #include "dyninstAPI/src/instP.h"
48 #include "dyninstAPI/src/ast.h"
49 #include "dyninstAPI/src/util.h"
50 #include "dyninstAPI/src/dyninstP.h"
51 #include "paradynd/src/metric.h"
52 #include "paradynd/src/internalMetrics.h"
53 #include "dyninstRPC.xdr.SRVR.h"
54 #include "dyninstAPI/src/dyninst.h"
55 #include "dyninstAPI/src/stats.h"
56 #include "paradynd/src/resource.h"
57 #include "paradynd/src/mdld.h"
58 #include "paradynd/src/init.h"
59 #include "paradynd/src/costmetrics.h"
60 #include "paradynd/src/context.h"
61 #include "dyninstAPI/src/showerror.h"
62 #include "common/h/debugOstream.h"
63 #include "pdutil/h/hist.h"
64
65 // The following were defined in process.C
66 extern debug_ostream attach_cerr;
67 extern debug_ostream inferiorrpc_cerr;
68 extern debug_ostream shmsample_cerr;
69 extern debug_ostream forkexec_cerr;
70 extern debug_ostream signal_cerr;
71
72 timeLength *imetricSamplingRate = NULL;
73 timeLength *currSamplingRate = NULL;
74
75 const timeLength &getIMetricSamplingRate() {
76   if(imetricSamplingRate == NULL) {
77     // default to once a second.
78     imetricSamplingRate = new timeLength(timeLength::sec());
79   }
80   return *imetricSamplingRate;
81 }
82
83 void setCurrSamplingRate(timeLength tl) {
84   if(currSamplingRate == NULL) {
85     currSamplingRate = new timeLength(BASEBUCKETWIDTH_SECS, timeUnit::sec());
86   }
87   *currSamplingRate = tl;
88 }
89
90 const timeLength &getCurrSamplingRate() {
91   if(currSamplingRate == NULL) {
92     currSamplingRate = new timeLength(BASEBUCKETWIDTH_SECS, timeUnit::sec());
93   }
94   return *currSamplingRate;
95 }
96
97 void dynRPC::printStats(void)
98 {
99   printDyninstStats();
100 }
101
102 // TODO -- use a different creation time
103 void dynRPC::addResource(u_int parent_id, u_int id, string name, u_int type)
104 {
105   resource *parent = resource::findResource(parent_id);
106   if (!parent) return;
107   resource::newResource(parent, name, id, type);
108 }
109
110 extern vector<process*> processVec;
111 extern process* findProcess(int); // should become a static method of class process
112
113 void dynRPC::coreProcess(int id)
114 {
115   process *proc = findProcess(id);
116   if (proc)
117     proc->dumpCore("core.out");
118 }
119
120 string dynRPC::getStatus(int id)
121 {
122   process *proc = findProcess(id);
123   if (!proc) {
124     string ret = string("PID: ") + string(id);
125     ret += string(" not found for getStatus\n");
126     return (P_strdup(ret.string_of()));
127   } else 
128     return (proc->getProcessStatus());
129 }
130
131 vector<T_dyninstRPC::metricInfo> dynRPC::getAvailableMetrics(void) {
132   vector<T_dyninstRPC::metricInfo> metInfo;
133   unsigned size = internalMetric::allInternalMetrics.size();
134   for (unsigned u=0; u<size; u++)
135     metInfo += internalMetric::allInternalMetrics[u]->getInfo();
136   for (unsigned u2=0; u2< costMetric::allCostMetrics.size(); u2++)
137     metInfo += costMetric::allCostMetrics[u2]->getInfo();
138   mdl_get_info(metInfo);
139   return(metInfo);
140 }
141
142 void dynRPC::getPredictedDataCost(u_int id,
143                                   u_int req_id,
144                                   vector<u_int> focus, 
145                                   string metName,
146                                   u_int clientID)
147 {
148     if (!metName.length()) 
149       getPredictedDataCostCallback(id, req_id, 0.0,clientID);
150     else{
151       timeLength cost = guessCost(metName, focus);
152          // note: returns 0.0 in a variety of situations (if metric cannot be
153          //       enabled, etc.)  Would we rather have a more explicit error
154          //       return value?
155       getPredictedDataCostCallback(id, req_id, 
156                      static_cast<float>(cost.getD(timeUnit::sec())), clientID);
157     }
158 }
159
160 void dynRPC::disableDataCollection(int mid)
161 {
162     metricDefinitionNode *mi;
163
164 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
165     begin_timing(1);
166 #endif
167
168     if (!allMIs.defines(mid)) {
169       // sprintf(errorLine, "Internal error: disableDataCollection mid %d not found\n", mid);
170       // logLine(errorLine);
171       // showErrorCallback(61,(const char *) errorLine);
172       // because of async enables this can happen, so ignore it
173       return;
174     }
175
176     mi = allMIs[mid];
177     // cout << "disable of " << mi->getFullName() << endl; 
178     // timeLength cost = mi->originalCost();
179     timeLength cost = mi->cost();
180     
181     if(cost > currentPredictedCost)
182         setCurrentPredictedCost(timeLength::Zero());
183     else 
184         subCurrentPredictedCost(cost);
185
186     vector<process *> procsToCont;
187     process *proc;
188     for (unsigned i=0; i<processVec.size(); i++) {
189       proc = processVec[i];
190       if (proc->status()==running) {
191 #ifdef DETACH_ON_THE_FLY
192          proc->reattachAndPause();
193 #else
194          proc->pause();
195 #endif
196         procsToCont += proc;
197       }
198       if (proc->existsRPCreadyToLaunch()) {
199         proc->cleanRPCreadyToLaunch(mid);
200       }
201     }
202
203     mi->disable();
204     for (unsigned p=0;p<procsToCont.size();p++) {
205 #ifdef DETACH_ON_THE_FLY
206       procsToCont[p]->detachAndContinue();
207 #else
208       procsToCont[p]->continueProc();
209 #endif
210     }
211     allMIs.undef(mid);
212     delete(mi);
213
214 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
215     end_timing(1,"disable");
216 #endif
217 }
218
219 bool dynRPC::setTracking(unsigned target, bool /* mode */)
220 {
221     resource *res = resource::findResource(target);
222     if (res) {
223         if (res->isResourceDescendent(moduleRoot)) {
224             res->suppress(true);
225             return(true);
226         } else {
227             // un-supported resource hierarchy.
228             return(false);
229         }
230     } else {
231       // cout << "Set tracking target " << target << " not found\n";
232       return(false);
233     }
234 }
235
236 void dynRPC::resourceInfoResponse(vector<u_int> temporaryIds, 
237                                   vector<u_int> resourceIds) {
238     assert(temporaryIds.size() == resourceIds.size());
239
240     for (unsigned u = 0; u < temporaryIds.size(); u++) {
241       resource *res = resource::findResource(temporaryIds[u]);
242       assert(res);
243       res->set_id(resourceIds[u]);
244     }
245 }
246
247
248 // TODO -- startCollecting  Returns -1 on failure ?
249 void dynRPC::enableDataCollection(vector<T_dyninstRPC::focusStruct> focus, 
250                               vector<string> metric,
251                               vector<u_int> mi_ids, 
252                               u_int daemon_id,
253                               u_int request_id){
254     vector<int> return_id;
255     assert(focus.size() == metric.size());
256     return_id.resize(metric.size());
257     totalInstTime.start();
258
259     vector<process *>procsToContinue;
260
261 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
262     begin_timing(0);
263 #endif
264
265     for (u_int i=0;i<metric.size();i++) {
266         return_id[i] = startCollecting(metric[i], focus[i].focus, mi_ids[i], 
267                                        procsToContinue);
268     }
269
270 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
271     end_timing(0,"enable");
272 #endif
273     
274     // continue the processes that were stopped in start collecting
275     for (unsigned u = 0; u < procsToContinue.size(); u++) {
276 #ifdef DETACH_ON_THE_FLY
277       procsToContinue[u]->detachAndContinue();
278 #else
279       procsToContinue[u]->continueProc();
280 #endif
281       // uncomment next line for debugging purposes on AIX
282       // procsToContinue[u]->detach(false);
283     }
284     totalInstTime.stop();
285
286     enableDataCallback(daemon_id,return_id,mi_ids,request_id);
287 }
288
289 // synchronous, for propogating metrics
290 int dynRPC::enableDataCollection2(vector<u_int> focus, string met, int gid)
291 {
292   int id;
293
294   totalInstTime.start();
295   vector<process *>procsToContinue;
296
297   id = startCollecting(met, focus, gid, procsToContinue);
298
299   for (unsigned u = 0; u < procsToContinue.size(); u++) {
300 #ifdef DETACH_ON_THE_FLY
301     procsToContinue[u]->detachAndContinue();
302 #else
303     procsToContinue[u]->continueProc();
304 #endif
305   }
306   totalInstTime.stop();
307   // cout << "Enabled " << met << " = " << id << endl;
308   return(id);
309 }
310
311 //
312 // computes new sample multiple value, and modifies the value of the
313 // symbol _DYNINSTsampleMultiple which will affect the frequency with
314 // which performance data is sent to the paradyn process 
315 //
316 void dynRPC::setSampleRate(double sampleInterval)
317 {
318     // TODO: implement this:
319     // want to change value of DYNINSTsampleMultiple to corr. to new
320     // sampleInterval (sampleInterval % baseSampleInterval) 
321     // if the sampleInterval is less than the BASESAMPLEINTERVAL ignore
322     // use currSamplingRate to determine if the change to DYNINSTsampleMultiple
323     // needs to be made
324     timeLength newSampleRate(timeLength(sampleInterval, timeUnit::sec()));
325
326     if(newSampleRate != getCurrSamplingRate()){
327       // sample_multiple:  .2 sec  => 1 ;  .4 sec => 2 ;  .8 sec => 4
328          int sample_multiple = static_cast<int>(
329            ((newSampleRate.getD(timeUnit::sec())+.01) / BASEBUCKETWIDTH_SECS));
330
331 //       char buffer[200];
332 //       sprintf(buffer, "ari fold; sampleInterval=%g so sample_multiple now %d\n",
333 //               sampleInterval, *sample_multiple);
334 //       logLine(buffer);
335          
336         // setSampleMultiple(sample_multiple);
337         // set the sample multiple in all processes
338         unsigned p_size = processVec.size();
339         for (unsigned u=0; u<p_size; u++){
340           if (processVec[u]->status() != exited) {
341             internalSym ret_sym; 
342             if(!(processVec[u]->findInternalSymbol("DYNINSTsampleMultiple",
343                                                              true, ret_sym))){
344                 sprintf(errorLine, "error2 in dynRPC::setSampleRate\n");
345                 logLine(errorLine);
346                 P_abort();
347             }
348             Address addr = ret_sym.getAddr();
349             processVec[u]->writeDataSpace((caddr_t)addr,sizeof(int),
350                                           (caddr_t)&sample_multiple);
351           }
352         }
353         setCurrSamplingRate(newSampleRate);
354         metricDefinitionNode::updateAllAggInterval(newSampleRate);
355     }
356     return;
357 }
358
359 bool dynRPC::detachProgram(int program, bool pause)
360 {
361   process *proc = findProcess(program);
362   if (proc)
363     return(proc->detach(pause));
364   else
365     return false;
366 }
367
368 //
369 // Continue all processes
370 //
371 void dynRPC::continueApplication(void)
372 {
373     continueAllProcesses();
374     statusLine("application running");
375 }
376
377 //
378 // Continue a process
379 //
380 void dynRPC::continueProgram(int program)
381 {
382     process *proc = findProcess(program);
383     if (!proc) {
384       sprintf(errorLine, "Internal error: cannot continue PID %d\n", program);
385       logLine(errorLine);
386       showErrorCallback(62,(const char *) errorLine,
387                         machineResource->part_name());
388       return;
389     }
390     if (proc->existsRPCinProgress())  {
391       // An RPC is in progress, so we delay the continueProc until the RPC
392       // finishes - naim
393       proc->deferredContinueProc=true;
394     } else {
395          if( proc->status() != running ) {
396 #ifdef DETACH_ON_THE_FLY
397                 proc->detachAndContinue();
398 #else
399                 proc->continueProc();
400 #endif
401          }
402          // we are no longer paused, are we?
403          statusLine("application running");
404          if (!markApplicationRunning()) {
405               return;
406          }
407     }
408 }
409
410 //
411 //  Stop all processes 
412 //
413 bool dynRPC::pauseApplication(void)
414 {
415     pauseAllProcesses();
416     return true;
417 }
418
419 //
420 //  Stop a single process
421 //
422 bool dynRPC::pauseProgram(int program)
423 {
424     process *proc = findProcess(program);
425     if (!proc) {
426       sprintf(errorLine, "Internal error: cannot pause PID %d\n", program);
427       logLine(errorLine);
428       showErrorCallback(63,(const char *) errorLine,
429                         machineResource->part_name());
430       return false;
431     }
432 #ifdef DETACH_ON_THE_FLY
433     return proc->reattachAndPause();
434 #else
435     return proc->pause();
436 #endif
437 }
438
439 bool dynRPC::startProgram(int )
440 {
441     statusLine("starting application");
442     continueAllProcesses();
443     return(false);
444 }
445
446 //
447 // Monitor the dynamic call sites contained in function <function_name>
448 //
449 void dynRPC::MonitorDynamicCallSites(string function_name){
450   unsigned i;
451   process *p;
452   for(i = 0; i < processVec.size(); i++){
453     p = processVec[i];
454     p->MonitorDynamicCallSites(function_name);
455   }
456 }
457
458 //
459 // start a new program for the tool.
460 //
461 int dynRPC::addExecutable(vector<string> argv, string dir)
462 {
463   vector<string> envp;
464   return(addProcess(argv, envp, dir)); // context.C
465 }
466
467
468 //
469 // Attach is the other way to start a process (application?)
470 // path gives the full path name to the executable, used _only_ to read
471 // the symbol table off disk.
472 // values for 'afterAttach': 1 --> pause, 2 --> run, 0 --> leave as is
473 //
474 bool dynRPC::attach(string progpath, int pid, int afterAttach)
475 {
476     attach_cerr << "WELCOME to dynRPC::attach" << endl;
477     attach_cerr << "progpath=" << progpath << endl;
478     attach_cerr << "pid=" << pid << endl;
479     attach_cerr << "afterAttach=" << afterAttach << endl;
480
481 #ifdef notdef
482     // This code is for Unix platforms only, it will not compile on Windows NT.
483     char *str = getenv("PARADYND_ATTACH_DEBUG");
484     if (str != NULL) {
485        cerr << "pausing paradynd pid " << getpid() << " before attachProcess()" << endl;
486        kill(getpid(), SIGSTOP);
487     }
488 #endif
489
490     return attachProcess(progpath, pid, afterAttach); // process.C
491 }
492
493 //
494 // report the current time 
495 //
496 double dynRPC::getTime() {
497   return getWallTime().getD(timeUnit::sec(), timeBase::bStd());
498 }