- Implemented fork support for x86-Linux, fixed fork support on
[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.71 1999/04/27 16:04:32 nash 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 "dyninstAPI/src/showerror.h"
61 #include "util/h/sys.h" 
62 #include "util/h/debugOstream.h"
63
64 // The following were defined in process.C
65 extern debug_ostream attach_cerr;
66 extern debug_ostream inferiorrpc_cerr;
67 extern debug_ostream shmsample_cerr;
68 extern debug_ostream forkexec_cerr;
69 extern debug_ostream metric_cerr;
70 extern debug_ostream signal_cerr;
71
72 #define ONEMILLION 1000000
73 // default to once a second.
74 float samplingRate = 1.0;
75 float currSamplingRate = BASEBUCKETWIDTH;
76
77 void dynRPC::printStats(void)
78 {
79   printDyninstStats();
80 }
81
82 // TODO -- use a different creation time
83 void dynRPC::addResource(u_int parent_id, u_int id, string name, u_int type)
84 {
85   resource *parent = resource::findResource(parent_id);
86   if (!parent) return;
87   resource::newResource(parent, name, id, type);
88 }
89
90 extern vector<process*> processVec;
91 extern process* findProcess(int); // should become a static method of class process
92
93 void dynRPC::coreProcess(int id)
94 {
95   process *proc = findProcess(id);
96   if (proc)
97     proc->dumpCore("core.out");
98 }
99
100 string dynRPC::getStatus(int id)
101 {
102   process *proc = findProcess(id);
103   if (!proc) {
104     string ret = string("PID: ") + string(id);
105     ret += string(" not found for getStatus\n");
106     return (P_strdup(ret.string_of()));
107   } else 
108     return (proc->getProcessStatus());
109 }
110
111 vector<T_dyninstRPC::metricInfo> dynRPC::getAvailableMetrics(void) {
112   vector<T_dyninstRPC::metricInfo> metInfo;
113   unsigned size = internalMetric::allInternalMetrics.size();
114   for (unsigned u=0; u<size; u++)
115     metInfo += internalMetric::allInternalMetrics[u]->getInfo();
116   for (unsigned u2=0; u2< costMetric::allCostMetrics.size(); u2++)
117     metInfo += costMetric::allCostMetrics[u2]->getInfo();
118   mdl_get_info(metInfo);
119   return(metInfo);
120 }
121
122 void dynRPC::getPredictedDataCost(u_int id,
123                                   u_int req_id,
124                                   vector<u_int> focus, 
125                                   string metName,
126                                   u_int clientID)
127 {
128     if (!metName.length()) 
129       getPredictedDataCostCallback(id, req_id, 0.0,clientID);
130     else{
131       float cost = guessCost(metName, focus);
132          // note: returns 0.0 in a variety of situations (if metric cannot be
133          //       enabled, etc.)  Would we rather have a more explicit error
134          //       return value?
135       getPredictedDataCostCallback(id, req_id, cost,clientID);
136     }
137 }
138
139 void dynRPC::disableDataCollection(int mid)
140 {
141     float cost;
142     metricDefinitionNode *mi;
143
144 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
145     begin_timing(1);
146 #endif
147
148     if (!allMIs.defines(mid)) {
149       // sprintf(errorLine, "Internal error: disableDataCollection mid %d not found\n", mid);
150       // logLine(errorLine);
151       // showErrorCallback(61,(const char *) errorLine);
152       // because of async enables this can happen, so ignore it
153       return;
154     }
155
156     mi = allMIs[mid];
157     // cout << "disable of " << mi->getFullName() << endl; 
158
159     cost = mi->originalCost();
160     
161     if(cost > currentPredictedCost)
162         currentPredictedCost = 0.0;
163     else 
164         currentPredictedCost -= cost;
165
166     vector<process *> procsToCont;
167     process *proc;
168     for (unsigned i=0; i<processVec.size(); i++) {
169       proc = processVec[i];
170       if (proc->status()==running) {
171         proc->pause();
172         procsToCont += proc;
173       }
174       if (proc->existsRPCreadyToLaunch()) {
175         proc->cleanRPCreadyToLaunch(mid);
176       }
177     }
178
179     mi->disable();
180     for (unsigned p=0;p<procsToCont.size();p++) {
181       procsToCont[p]->continueProc();
182     }
183     allMIs.undef(mid);
184     delete(mi);
185
186 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
187     end_timing(1,"disable");
188 #endif
189 }
190
191 bool dynRPC::setTracking(unsigned target, bool mode)
192 {
193     resource *res = resource::findResource(target);
194     if (res) {
195         if (res->isResourceDescendent(moduleRoot)) {
196             image::changeLibFlag(res, (bool) mode);
197             res->suppress(true);
198             return(true);
199         } else {
200             // un-supported resource hierarchy.
201             return(false);
202         }
203     } else {
204       // cout << "Set tracking target " << target << " not found\n";
205       return(false);
206     }
207 }
208
209 void dynRPC::resourceInfoResponse(vector<u_int> temporaryIds, 
210                                   vector<u_int> resourceIds) {
211     assert(temporaryIds.size() == resourceIds.size());
212
213     for (unsigned u = 0; u < temporaryIds.size(); u++) {
214       resource *res = resource::findResource(temporaryIds[u]);
215       assert(res);
216       res->set_id(resourceIds[u]);
217     }
218 }
219
220
221 // in response to memoryInfoCallback, pass the handles back
222 //
223 memory *theMemory = new memory;
224
225 void dynRPC::memoryRangeSelected(string flat, int min, int max)
226 {
227         theMemory->setCurrentBounds(flat, min, max) ;
228 }
229
230
231 void dynRPC::memoryInfoResponse(string          data_structure_name,
232                                 int             virtual_address,
233                                 u_int           memory_size,
234                                 u_int           cache_blk_size,
235                                 vector<u_int>   resource_ids)
236 {
237         //Obtain the highest and lowest memory addresses
238         static int cache_blk_size_has_been_set= 0 ;
239         theMemory->updateGlobalBounds(virtual_address, memory_size) ;
240         if(!cache_blk_size_has_been_set)
241         {
242                 theMemory->setBlkSize(cache_blk_size) ;
243                 cache_blk_size_has_been_set = 1 ;
244         }
245
246         //buildup the memory resource
247         int i = 0 ;
248         int vend = virtual_address + memory_size ;
249         vector<string> parent_name ;
250         vector<string> resource_name ;
251
252         resource *parent = NULL ;
253         resource *res ;
254         const char *name = data_structure_name.string_of() ;
255         char temp[255] ;
256
257         parent_name += "Memory" ;
258         resource_name += "Memory" ;
259
260         sprintf(temp, "%s", name) ;
261         if ((parent = resource::findResource(parent_name)))
262         {
263                 // record the boundry of the variable
264                 memory::bounds b ;
265                 b.lower = virtual_address ;
266                 b.upper = virtual_address + memory_size -1 ;
267                 theMemory->setVariableBounds(string(name), b) ;
268
269                 resource_name += name ;
270                 res = resource::newResource_ncb(parent, NULL, "BASE", temp, 0.0, "", MDL_T_VARIABLE);
271                 if (res) res->set_id(resource_ids[i]);
272                 i++ ;
273                 parent_name += name ;
274         }
275         if((parent = resource::findResource(parent_name)) )
276         {
277           
278                 while(virtual_address < vend)
279                 {
280                         sprintf(temp, "%d", (int) virtual_address) ;
281                         res = resource::newResource_ncb(parent, NULL, "BASE", temp, 0.0, "", MDL_T_INT);
282                         if (res) res->set_id(resource_ids[i]);
283                         i++ ;
284                         virtual_address += cache_blk_size ;
285                 }
286         }
287 }
288
289
290
291 // TODO -- startCollecting  Returns -1 on failure ?
292 void dynRPC::enableDataCollection(vector<T_dyninstRPC::focusStruct> focus, 
293                               vector<string> metric,
294                               vector<u_int> mi_ids, 
295                               u_int daemon_id,
296                               u_int request_id){
297     vector<int> return_id;
298     assert(focus.size() == metric.size());
299     return_id.resize(metric.size());
300     totalInstTime.start();
301
302     vector<process *>procsToContinue;
303
304 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
305     begin_timing(0);
306 #endif
307
308     for (u_int i=0;i<metric.size();i++) {
309         return_id[i] = startCollecting(metric[i], focus[i].focus, mi_ids[i],                                          procsToContinue);
310     }
311
312 #if defined(sparc_sun_solaris2_4) && defined(TIMINGDEBUG)
313     end_timing(0,"enable");
314 #endif
315
316     // continue the processes that were stopped in start collecting
317     for (unsigned u = 0; u < procsToContinue.size(); u++)
318       procsToContinue[u]->continueProc();
319       // uncomment next line for debugging purposes on AIX
320       // procsToContinue[u]->detach(false);
321
322     totalInstTime.stop();
323
324     enableDataCallback(daemon_id,return_id,mi_ids,request_id);
325 }
326
327 int dynRPC::enableDataCollection2(vector<u_int> focus, string met, int gid)
328 {
329   int id;
330
331   totalInstTime.start();
332   vector<process *>procsToContinue;
333
334   id = startCollecting(met, focus, gid, procsToContinue);
335
336   for (unsigned u = 0; u < procsToContinue.size(); u++)
337     procsToContinue[u]->continueProc();
338   totalInstTime.stop();
339   // cout << "Enabled " << met << " = " << id << endl;
340   return(id);
341 }
342
343 //
344 // computes new sample multiple value, and modifies the value of the
345 // symbol _DYNINSTsampleMultiple which will affect the frequency with
346 // which performance data is sent to the paradyn process 
347 //
348 void dynRPC::setSampleRate(double sampleInterval)
349 {
350     // TODO: implement this:
351     // want to change value of DYNINSTsampleMultiple to corr. to new
352     // sampleInterval (sampleInterval % baseSampleInterval) 
353     // if the sampleInterval is less than the BASESAMPLEINTERVAL ignore
354     // use currSamplingRate to determine if the change to DYNINSTsampleMultiple
355     // needs to be made
356
357     // TODO:
358     // Update the value of bucket_width, an internal metric.
359     // (Code used to be here to update the value, but it wasn't quite enough.
360     //  In particular, if there were no enabled instances of bucket_width, then
361     //  no updating would be done; thus the update could get lost.
362     //  Example: put up table with active_processes; run program 5 seconds;
363     //           then add bucket_width to the table.  The bucket width will be 0
364     //           because the routine that updated bucket width (i.e. right here)
365     //           was called only after active_processes was added; not after
366     //           bucket_width was added.
367     // In metric.C, we work around the problem by putting in a kludge for reporting
368     // the internal metric bucket_width; we simply ignore the value stored in the
369     // internalMetrics class and instead return the extern float "sampleInterval" --ari
370     //
371     // We keep the following code because it's harmless; but remember, it's also
372     // not really being used at this time:
373     if (bucket_width->num_enabled_instances() > 0)
374        bucket_width->getEnabledInstance(0).setValue(sampleInterval);
375
376     if(sampleInterval != currSamplingRate){
377          int sample_multiple = (int)((sampleInterval*ONEMILLION)/BASESAMPLEINTERVAL);
378
379 //       char buffer[200];
380 //       sprintf(buffer, "ari fold; sampleInterval=%g so sample_multiple now %d\n",
381 //               sampleInterval, *sample_multiple);
382 //       logLine(buffer);
383          
384         // setSampleMultiple(sample_multiple);
385         // set the sample multiple in all processes
386         unsigned p_size = processVec.size();
387         for (unsigned u=0; u<p_size; u++){
388           if (processVec[u]->status() != exited) {
389             internalSym ret_sym; 
390             if(!(processVec[u]->findInternalSymbol("DYNINSTsampleMultiple",
391                                                              true, ret_sym))){
392                 sprintf(errorLine, "error2 in dynRPC::setSampleRate\n");
393                 logLine(errorLine);
394                 P_abort();
395             }
396             Address addr = ret_sym.getAddr();
397             processVec[u]->writeDataSpace((caddr_t)addr,sizeof(int),
398                                           (caddr_t)&sample_multiple);
399           }
400         }
401
402         currSamplingRate = sampleInterval;
403         cerr << "dynrpc: currSamplingRate set to " << currSamplingRate << endl;
404     }
405     return;
406 }
407
408 bool dynRPC::detachProgram(int program, bool pause)
409 {
410   process *proc = findProcess(program);
411   if (proc)
412     return(proc->detach(pause));
413   else
414     return false;
415 }
416
417 //
418 // Continue all processes
419 //
420 void dynRPC::continueApplication(void)
421 {
422     continueAllProcesses();
423     statusLine("application running");
424 }
425
426 //
427 // Continue a process
428 //
429 void dynRPC::continueProgram(int program)
430 {
431     process *proc = findProcess(program);
432     if (!proc) {
433       sprintf(errorLine, "Internal error: cannot continue PID %d\n", program);
434       logLine(errorLine);
435       showErrorCallback(62,(const char *) errorLine,
436                         machineResource->part_name());
437     }
438     if (proc->existsRPCinProgress())  {
439       // An RPC is in progress, so we delay the continueProc until the RPC
440       // finishes - naim
441       proc->deferredContinueProc=true;
442     } else {
443           if( proc->status() != running )
444                 proc->continueProc();
445       statusLine("application running");
446     }
447 }
448
449 //
450 //  Stop all processes 
451 //
452 bool dynRPC::pauseApplication(void)
453 {
454     pauseAllProcesses();
455     return true;
456 }
457
458 //
459 //  Stop a single process
460 //
461 bool dynRPC::pauseProgram(int program)
462 {
463     process *proc = findProcess(program);
464     if (!proc) {
465       sprintf(errorLine, "Internal error: cannot pause PID %d\n", program);
466       logLine(errorLine);
467       showErrorCallback(63,(const char *) errorLine,
468                         machineResource->part_name());
469       return false;
470     }
471     return (proc->pause());
472 }
473
474 bool dynRPC::startProgram(int )
475 {
476     statusLine("starting application");
477     continueAllProcesses();
478     return(false);
479 }
480
481 //
482 // start a new program for the tool.
483 //
484 int dynRPC::addExecutable(vector<string> argv, string dir)
485 {
486   vector<string> envp;
487   return(addProcess(argv, envp, dir)); // context.C
488 }
489
490
491 //
492 // Attach is the other way to start a process (application?)
493 // path gives the full path name to the executable, used _only_ to read
494 // the symbol table off disk.
495 // values for 'afterAttach': 1 --> pause, 2 --> run, 0 --> leave as is
496 //
497 bool dynRPC::attach(string progpath, int pid, int afterAttach)
498 {
499     attach_cerr << "WELCOME to dynRPC::attach" << endl;
500     attach_cerr << "progpath=" << progpath << endl;
501     attach_cerr << "pid=" << pid << endl;
502     attach_cerr << "afterAttach=" << afterAttach << endl;
503
504 #ifdef notdef
505     // This code is for Unix platforms only, it will not compile on Windows NT.
506     char *str = getenv("PARADYND_ATTACH_DEBUG");
507     if (str != NULL) {
508        cerr << "pausing paradynd pid " << getpid() << " before attachProcess()" << endl;
509        kill(getpid(), SIGSTOP);
510     }
511 #endif
512
513     return attachProcess(progpath, pid, afterAttach); // process.C
514 }
515
516 //
517 // report the current time 
518 //
519 double dynRPC::getTime() {
520   return getCurrentTime(false);
521 }