2 * Copyright (c) 1996 Barton P. Miller
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.
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.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
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.
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.
42 /* $Id: dynrpc.C,v 1.84 2001/08/23 14:44:04 schendel Exp $ */
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"
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;
72 timeLength *imetricSamplingRate = NULL;
73 timeLength *currSamplingRate = NULL;
75 const timeLength &getIMetricSamplingRate() {
76 if(imetricSamplingRate == NULL) {
77 // default to once a second.
78 imetricSamplingRate = new timeLength(timeLength::sec());
80 return *imetricSamplingRate;
83 void setCurrSamplingRate(timeLength tl) {
84 if(currSamplingRate == NULL) {
85 currSamplingRate = new timeLength(BASEBUCKETWIDTH_SECS, timeUnit::sec());
87 *currSamplingRate = tl;
90 const timeLength &getCurrSamplingRate() {
91 if(currSamplingRate == NULL) {
92 currSamplingRate = new timeLength(BASEBUCKETWIDTH_SECS, timeUnit::sec());
94 return *currSamplingRate;
97 void dynRPC::printStats(void)
102 // TODO -- use a different creation time
103 void dynRPC::addResource(u_int parent_id, u_int id, string name, u_int type)
105 resource *parent = resource::findResource(parent_id);
107 resource::newResource(parent, name, id, type);
110 extern vector<process*> processVec;
111 extern process* findProcess(int); // should become a static method of class process
113 void dynRPC::coreProcess(int id)
115 process *proc = findProcess(id);
117 proc->dumpCore("core.out");
120 string dynRPC::getStatus(int id)
122 process *proc = findProcess(id);
124 string ret = string("PID: ") + string(id);
125 ret += string(" not found for getStatus\n");
126 return (P_strdup(ret.string_of()));
128 return (proc->getProcessStatus());
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);
142 void dynRPC::getPredictedDataCost(u_int id,
148 if (!metName.length())
149 getPredictedDataCostCallback(id, req_id, 0.0,clientID);
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
155 getPredictedDataCostCallback(id, req_id,
156 static_cast<float>(cost.getD(timeUnit::sec())), clientID);
160 void dynRPC::disableDataCollection(int mid)
162 metricDefinitionNode *mi;
164 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
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
177 // cout << "disable of " << mi->getFullName() << endl;
178 // timeLength cost = mi->originalCost();
179 timeLength cost = mi->cost();
181 if(cost > currentPredictedCost)
182 setCurrentPredictedCost(timeLength::Zero());
184 subCurrentPredictedCost(cost);
186 vector<process *> procsToCont;
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();
198 if (proc->existsRPCreadyToLaunch()) {
199 proc->cleanRPCreadyToLaunch(mid);
204 for (unsigned p=0;p<procsToCont.size();p++) {
205 #ifdef DETACH_ON_THE_FLY
206 procsToCont[p]->detachAndContinue();
208 procsToCont[p]->continueProc();
214 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
215 end_timing(1,"disable");
219 bool dynRPC::setTracking(unsigned target, bool /* mode */)
221 resource *res = resource::findResource(target);
223 if (res->isResourceDescendent(moduleRoot)) {
227 // un-supported resource hierarchy.
231 // cout << "Set tracking target " << target << " not found\n";
236 void dynRPC::resourceInfoResponse(vector<u_int> temporaryIds,
237 vector<u_int> resourceIds) {
238 assert(temporaryIds.size() == resourceIds.size());
240 for (unsigned u = 0; u < temporaryIds.size(); u++) {
241 resource *res = resource::findResource(temporaryIds[u]);
243 res->set_id(resourceIds[u]);
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,
254 vector<int> return_id;
255 assert(focus.size() == metric.size());
256 return_id.resize(metric.size());
257 totalInstTime.start();
259 vector<process *>procsToContinue;
261 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
265 for (u_int i=0;i<metric.size();i++) {
266 return_id[i] = startCollecting(metric[i], focus[i].focus, mi_ids[i],
270 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
271 end_timing(0,"enable");
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();
279 procsToContinue[u]->continueProc();
281 // uncomment next line for debugging purposes on AIX
282 // procsToContinue[u]->detach(false);
284 totalInstTime.stop();
286 enableDataCallback(daemon_id,return_id,mi_ids,request_id);
289 // synchronous, for propogating metrics
290 int dynRPC::enableDataCollection2(vector<u_int> focus, string met, int gid)
294 totalInstTime.start();
295 vector<process *>procsToContinue;
297 id = startCollecting(met, focus, gid, procsToContinue);
299 for (unsigned u = 0; u < procsToContinue.size(); u++) {
300 #ifdef DETACH_ON_THE_FLY
301 procsToContinue[u]->detachAndContinue();
303 procsToContinue[u]->continueProc();
306 totalInstTime.stop();
307 // cout << "Enabled " << met << " = " << id << endl;
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
316 void dynRPC::setSampleRate(double sampleInterval)
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
324 timeLength newSampleRate(timeLength(sampleInterval, timeUnit::sec()));
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));
332 // sprintf(buffer, "ari fold; sampleInterval=%g so sample_multiple now %d\n",
333 // sampleInterval, *sample_multiple);
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) {
342 if(!(processVec[u]->findInternalSymbol("DYNINSTsampleMultiple",
344 sprintf(errorLine, "error2 in dynRPC::setSampleRate\n");
348 Address addr = ret_sym.getAddr();
349 processVec[u]->writeDataSpace((caddr_t)addr,sizeof(int),
350 (caddr_t)&sample_multiple);
353 setCurrSamplingRate(newSampleRate);
354 metricDefinitionNode::updateAllAggInterval(newSampleRate);
359 bool dynRPC::detachProgram(int program, bool pause)
361 process *proc = findProcess(program);
363 return(proc->detach(pause));
369 // Continue all processes
371 void dynRPC::continueApplication(void)
373 continueAllProcesses();
374 statusLine("application running");
378 // Continue a process
380 void dynRPC::continueProgram(int program)
382 process *proc = findProcess(program);
384 sprintf(errorLine, "Internal error: cannot continue PID %d\n", program);
386 showErrorCallback(62,(const char *) errorLine,
387 machineResource->part_name());
390 if (proc->existsRPCinProgress()) {
391 // An RPC is in progress, so we delay the continueProc until the RPC
393 proc->deferredContinueProc=true;
395 if( proc->status() != running ) {
396 #ifdef DETACH_ON_THE_FLY
397 proc->detachAndContinue();
399 proc->continueProc();
402 // we are no longer paused, are we?
403 statusLine("application running");
404 if (!markApplicationRunning()) {
411 // Stop all processes
413 bool dynRPC::pauseApplication(void)
420 // Stop a single process
422 bool dynRPC::pauseProgram(int program)
424 process *proc = findProcess(program);
426 sprintf(errorLine, "Internal error: cannot pause PID %d\n", program);
428 showErrorCallback(63,(const char *) errorLine,
429 machineResource->part_name());
432 #ifdef DETACH_ON_THE_FLY
433 return proc->reattachAndPause();
435 return proc->pause();
439 bool dynRPC::startProgram(int )
441 statusLine("starting application");
442 continueAllProcesses();
447 // Monitor the dynamic call sites contained in function <function_name>
449 void dynRPC::MonitorDynamicCallSites(string function_name){
452 for(i = 0; i < processVec.size(); i++){
454 p->MonitorDynamicCallSites(function_name);
459 // start a new program for the tool.
461 int dynRPC::addExecutable(vector<string> argv, string dir)
464 return(addProcess(argv, envp, dir)); // context.C
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
474 bool dynRPC::attach(string progpath, int pid, int afterAttach)
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;
482 // This code is for Unix platforms only, it will not compile on Windows NT.
483 char *str = getenv("PARADYND_ATTACH_DEBUG");
485 cerr << "pausing paradynd pid " << getpid() << " before attachProcess()" << endl;
486 kill(getpid(), SIGSTOP);
490 return attachProcess(progpath, pid, afterAttach); // process.C
494 // report the current time
496 double dynRPC::getTime() {
497 return getWallTime().getD(timeUnit::sec(), timeBase::bStd());