Fixed performance consultant to prevent call graph based searches from
[dyninst.git] / paradyn / src / DMthread / DMpublic.C
1 /*
2  * Copyright (c) 1996-1998 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: DMpublic.C,v 1.108 1999/05/26 22:49:53 cain Exp $
43
44 extern "C" {
45 #include <malloc.h>
46 }
47
48 #include <assert.h>
49 #include <stdio.h>
50 #include <iostream.h>
51 #include <fstream.h>
52 #include "dataManager.thread.h"
53 #include "dataManager.thread.SRVR.h"
54 #include "dataManager.thread.CLNT.h"
55 #include "dyninstRPC.xdr.CLNT.h"
56 #include "visi.xdr.h"
57 #include "util/h/sys.h"
58 #include "util/h/Vector.h"
59 #include "util/h/Dictionary.h"
60 #include "util/h/makenan.h"
61 #include "DMmetric.h"
62 #include "DMdaemon.h"
63 #include "DMresource.h"
64 #include "DMperfstream.h"
65 #include "DMphase.h"
66 #include "DMinclude.h"
67 #include "paradyn/src/DMthread/DVbufferpool.h"
68 #include "paradyn/src/pdMain/paradyn.h"
69 #include "CallGraph.h"
70
71 // the argument list passed to paradynds
72 vector<string> paradynDaemon::args = 0;
73 extern bool our_print_sample_arrival;
74
75 void histDataCallBack(sampleValue *buckets,
76                       timeStamp,
77                       int count,
78                       int first,
79                       void *arg,
80                       bool globalFlag)
81 {
82     metricInstance *mi = (metricInstance *) arg;
83     performanceStream *ps = 0;
84
85 #ifdef n_def
86     // debug code that uses tunable constant printSampleArrival
87     if (our_print_sample_arrival){
88         cout << "bucket:  " << first << "value: "
89              << buckets[0] << "   bucketwidth " 
90              << metricInstance::GetGlobalWidth() <<  endl;
91     }
92 #endif
93
94     if(globalFlag) { 
95         // update global data
96         for(unsigned i=0; i < mi->global_users.size(); i++) {
97             ps = performanceStream::find(mi->global_users[i]); 
98             if(ps) {
99                 ps->callSampleFunc(mi->getHandle(), 
100                                    buckets, count, first,GlobalPhase);
101             }
102         }
103       }
104
105     else {  // update just curr. phase data
106         for(unsigned i=0; i < mi->users.size(); i++) {
107             ps = performanceStream::find(mi->users[i]); 
108             if(ps)
109                 ps->callSampleFunc(mi->getHandle(), 
110                                    buckets, count, first,CurrentPhase);
111         }
112       }
113
114     for(int i=first; i < count; i++){
115         if(buckets[i] < 0) printf("bucket %d : %f \n",i,buckets[i]);
116     }
117 }
118
119 //
120 // start_time specifies the phaseType (globalType starts at 0.0) 
121 //
122 void histFoldCallBack(timeStamp width, void *, bool globalFlag)
123 {
124     if(globalFlag){
125       // only notify clients if new bucket width is larger than previous one
126       if(metricInstance::GetGlobalWidth() < width) {
127         metricInstance::SetGlobalWidth(width);
128         performanceStream::foldAll(width,GlobalPhase);
129         if(!metricInstance::numCurrHists()){  // change the sampling rate
130           newSampleRate(width);
131         }
132       }
133     }
134     else {  // fold applies to current phase
135         // only notify clients if new bucket width is larger than previous one
136         if(metricInstance::GetCurrWidth() <  width) {
137             metricInstance::SetCurrWidth(width);
138             performanceStream::foldAll(width,CurrentPhase);
139             newSampleRate(width); // change sampling rate
140         }
141         phaseInfo::setCurrentBucketWidth(width);
142     }
143 }
144
145 // trace data streams
146 void traceDataCallBack(const void *data,
147                        int length,
148                        void *arg)
149 {
150     metricInstance *mi = (metricInstance *) arg;
151     performanceStream *ps = 0;
152     for(unsigned i=0; i < mi->trace_users.size(); i++) {
153          ps = performanceStream::find(mi->trace_users[i]);
154          if(ps) {
155              ps->callTraceFunc(mi->getHandle(),
156                                data,length);
157          }
158     }
159 }
160
161
162 void dataManager::setResourceSearchSuppress(resourceHandle res, bool newValue)
163 {
164     resource *r = resource::handle_to_resource(res);
165     if(r)
166         r->setSuppress(newValue);
167 }
168
169 void dataManager::setResourceSearchChildrenSuppress(resourceHandle res, 
170                                                     bool newValue)
171 {
172     resource *r = resource::handle_to_resource(res);
173     if(r) r->setSuppressChildren(newValue);
174 }
175
176 void dataManager::setResourceInstSuppress(resourceHandle res, bool newValue)
177 {
178     resource *r = resource::handle_to_resource(res);
179     if (r) paradynDaemon::setInstSuppress(r, newValue);
180 }
181
182 bool dataManager::addDaemon(const char *machine,
183                             const char *login,
184                             const char *name)
185 {
186   // fix args so that if char * points to "" then it pts to NULL
187   string m = 0;
188   if(machine && strlen(machine))  m = machine;
189   string l = 0;
190   if(login && strlen(login)) l = login;
191   string n = 0;
192   if(!name) { 
193       char *temp = 0; 
194       if(!paradynDaemon::setDefaultArgs(temp))
195           return false;
196       n = temp;
197       delete temp;
198   }
199   else {
200       n = name;
201   }
202   return (paradynDaemon::getDaemon(m, l, n));
203 }
204
205 //
206 // define a new entry for the daemon dictionary
207 //
208 bool dataManager::defineDaemon(const char *command,
209                                const char *dir,
210                                const char *login,
211                                const char *name,
212                                const char *machine,
213                                    const char *remote_shell,
214                                const char *flavor)
215 {
216   if(!name || !command)
217       return false;
218   return (paradynDaemon::defineDaemon(command, dir, login, name, machine, remote_shell, flavor));
219 }
220
221
222 bool dataManager::addExecutable(const char *machine,
223                                 const char *login,
224                                 const char *name,
225                                 const char *dir,
226                                 const vector<string> *argv)
227 {
228   // This is the implementation of an igen call...usually from the UI thread
229   // when a new process is defined in the dialog box.
230   string m = machine;
231   string l = login;
232   string n = name;
233   string d = dir;
234
235   return(paradynDaemon::newExecutable(m, l, n, d, *argv));
236 }
237
238
239 bool dataManager::attach(const char *machine,
240                          const char *user,
241                          const char *cmd, // program name (full path)
242                          const char *pidStr,
243                          const char *daemonName,
244                          int afterAttach // 0 --> as is, 1 --> pause, 2 --> run
245                          ) {
246    if (pidStr == NULL && cmd == NULL)
247       return false;
248
249    // cmd gives the full path to the executable...we use it just to read
250    // the symbol table.
251
252    int pid = pidStr ? atoi(pidStr) : -1;
253    return (paradynDaemon::attachStub(machine, user, cmd, pid, daemonName, afterAttach));
254       // "Stub" appended to name to avoid name clash with the actual remote igen call
255       // attach()
256 }
257
258 bool dataManager::applicationDefined()
259 {
260     return(paradynDaemon::applicationDefined());
261 }
262
263 bool dataManager::startApplication()
264 {
265     return(paradynDaemon::startApplication());
266 }
267
268 bool dataManager::pauseApplication()
269 {
270     return(paradynDaemon::pauseAll());
271 }
272
273 void dataManager::createCallGraph(){
274   CallGraph *cg = CallGraph::GetCallGraph(0);
275   cg->displayCallGraph();
276 }
277
278 bool dataManager::pauseProcess(int pid)
279 {
280     return(paradynDaemon::pauseProcess(pid));
281 }
282
283 bool dataManager::continueApplication()
284 {
285     return(paradynDaemon::continueAll());
286 }
287
288 bool dataManager::continueProcess(int pid)
289 {
290     return(paradynDaemon::continueProcess(pid));
291 }
292
293 bool dataManager::detachApplication(bool pause)
294 {
295    return(paradynDaemon::detachApplication(pause));
296 }
297
298 // 
299 // write all global data to files created in the dirname directory
300 // 
301 void dataManager::saveAllData (const char *dirname, SaveRequestType optionFlag) 
302 {
303   int findex = 0;
304   bool success = true;
305   metricInstance *activeMI;
306   string dir = string (dirname);
307   dir += string("/");
308
309   // create index file
310   string indexFileName = dir + "index";
311
312   ofstream indexFile (indexFileName.string_of(), ios::out);
313   if (!indexFile) {
314     success = false;
315   } else {
316
317     vector<metricInstanceHandle> allMIHs = 
318       metricInstance::allMetricInstances.keys();
319     for (unsigned i = 0; i < allMIHs.size(); i++) {
320       // try to write data from one metric instance 
321       activeMI = metricInstance::getMI(allMIHs[i]);
322       if (activeMI == NULL)
323         continue;
324
325       if ((optionFlag == Phase) || (optionFlag == All)) {
326         // save all phase data
327         string fileSuffix = string("hist_") + string(findex);
328         string miFileName = dir + fileSuffix;
329         
330         ofstream activeFile (miFileName.string_of(), ios::out);
331         if (!activeFile)
332           continue;
333         activeFile << "histogram " << activeMI->getMetricName() << endl <<  
334           activeMI->getFocusName() << endl;
335         
336         activeMI->saveAllData (activeFile, CurrentPhase);
337         indexFile << fileSuffix.string_of() << " " << activeMI->getMetricName()
338           << " " << activeMI->getFocusName() << endl;
339         findex++;  // increment fileid
340         // add index entry
341         activeFile.close();
342       } 
343       if ((optionFlag == Global) || (optionFlag == All)) { 
344         // save all global data
345         string fileSuffix = string("hist_") + string(findex);
346         string miFileName = dir + fileSuffix;
347
348         ofstream activeFile (miFileName.string_of(), ios::out);
349         if (!activeFile)
350           continue;
351         activeFile << "histogram " << activeMI->getMetricName() << endl <<  
352           activeMI->getFocusName() << endl;
353         activeMI->saveAllData (activeFile, GlobalPhase);
354         indexFile << fileSuffix.string_of() << " " <<  
355           activeMI->getMetricName() << " " << activeMI->getFocusName() << endl;
356         findex++;  // increment fileid
357         // add index entry
358         activeFile.close();
359       }
360     }
361     indexFile.close();
362   }
363   uiMgr->allDataSaved(success);
364 }
365
366 void
367 dataManager::saveAllResources (const char *dirname)
368 {
369   bool success = true;
370   string dir = string (dirname) + string("/resources");
371
372   ofstream saveFile (dir.string_of(), ios::out);
373   if (!saveFile) {
374     success = false;
375   } else {
376     resource::saveHierarchiesToFile(saveFile);
377     saveFile.close();
378   }
379   uiMgr->resourcesSaved(success);
380 }
381
382 perfStreamHandle dataManager::createPerformanceStream(dataType dt,
383                                                       dataCallback dc,
384                                                       controlCallback cc)
385 {
386     int td;
387     performanceStream *ps;
388
389     td = getRequestingThread();
390     ps = new performanceStream(dt, dc, cc, td);
391     return(ps->Handle());
392     ps = 0;
393 }
394
395 int dataManager::destroyPerformanceStream(perfStreamHandle handle){
396
397     performanceStream *ps = performanceStream::find(handle);
398     if(!ps) return(0);
399     delete ps;
400     return(1);
401 }
402
403 //
404 // If "all" is true, then all metrics will be passed regardless the mode.
405 // Otherwise, only those metrics corresponding to the current mode will be
406 // passed.
407 //
408 vector<string> *dataManager::getAvailableMetrics(bool all)
409 {
410     return(metric::allMetricNames(all));
411 }
412
413 //
414 // Same comments as for getAvailableMetrics
415 //
416 vector<met_name_id> *dataManager::getAvailableMetInfo(bool all)
417 {
418     return(metric::allMetricNamesIds(all));
419 }
420
421
422 metricHandle *dataManager::findMetric(const char *name)
423 {
424     string n = name;
425     const metricHandle *met = metric::find(n);
426     if(met){
427         metricHandle *ret = new metricHandle;
428         *ret = *met;
429         return(ret);
430     }
431     return 0;
432 }
433
434 vector<resourceHandle> *dataManager::getRootResources()
435 {
436     return(resource::rootResource->getChildren());
437 }
438
439 resourceHandle *dataManager::getRootResource()
440 {
441     resourceHandle *rh = new resourceHandle;
442     *rh = resource::rootResource->getHandle();
443     return(rh);
444 }
445
446 //
447 // make batched enable request to paradyn daemons
448 //
449 void DMdoEnableData(perfStreamHandle ps_handle,
450                     perfStreamHandle pt_handle,
451                     vector<metricRLType> *request,
452                     u_int request_Id,
453                     phaseType type,
454                     phaseHandle phaseId,
455                     u_int persistent_data,
456                     u_int persistent_collection,
457                     u_int phase_persistent_data){
458
459     vector<metricInstance *> *miVec = new vector<metricInstance *>;
460     vector<bool> *enabled = new vector<bool>;  // passed to daemons on enable
461     vector<bool> *done = new vector<bool>;  // used for waiting list
462
463    // for each element in list determine if this metric/focus pair is
464    // already enabled, or is currently being enabled: "enabled" is used to 
465    // indicate whether an enable call needs to be made to the daemon, "done"
466    // indicates if the request needs to wait for a reply from the daemon
467    // "mi" indicates if the metric/focus pair exists
468    //
469    //           not enabled     curr. enabling  error   enabled    
470    //           -----------------------------------------------
471    // done      |  false           false        true    true
472    // enabled   |  false           true         true    true
473    // mi*       |  &mi             &mi            0     &mi
474    //
475    bool need_to_enable = false;
476    bool need_to_wait = false;
477    for(u_int i=0; i < request->size(); i++){
478        // does this metric/focus pair already exist?
479        metricInstance *mi = metricInstance::find((*request)[i].met,
480                                                  (*request)[i].res);
481        if(!mi){ // create new metricInstance 
482            mi = new metricInstance((*request)[i].res,(*request)[i].met,phaseId);
483        }
484        *miVec += mi;
485        if(!mi){  // error case, don't try to enable this mi
486            *enabled += true;
487            *done += true;
488        }
489        else if(!mi->isEnabled()){  // mi not enabled
490            if(mi->isCurrentlyEnabling()){
491                *enabled += true;  // don't try to enable from daemons
492                *done += false;   // need to wait for result
493                need_to_wait = true;
494            }
495            else{
496                *enabled += false;
497                *done += false;  
498                need_to_enable = true;
499            }
500        }
501        else{ // mi already is enabled
502            *enabled += true;
503            *done += true;
504        }
505    }
506
507    assert(enabled->size() == done->size());
508    assert(enabled->size() == miVec->size());
509    assert(enabled->size() == request->size());
510
511    DM_enableType *new_entry = new DM_enableType(ps_handle,pt_handle,type,phaseId,
512                             paradynDaemon::next_enable_id++,request_Id,
513                             miVec,done,enabled,paradynDaemon::allDaemons.size(),
514                             persistent_data,persistent_collection,
515                             phase_persistent_data);
516
517    // if there is an MI that has not been enabled yet make enable 
518    // request to daemons or if there is an MI that is currently being
519    // enabled then put request on the outstanding requests list
520    if(need_to_enable || need_to_wait){
521        // for each MI on the request list set increment the EnablesWaiting
522        // flag for the correct phase.  These flags are decremented before
523        // the response is sent to the client
524        if(type == CurrentPhase){
525            for(u_int k=0; k < miVec->size(); k++){
526                if((*miVec)[k]) (*miVec)[k]->incrCurrWaiting(); 
527            }
528        } else{
529            for(u_int k=0; k < miVec->size(); k++){
530                if((*miVec)[k]) (*miVec)[k]->incrGlobalWaiting(); 
531            }
532        }
533        paradynDaemon::enableData(miVec,done,enabled,new_entry,need_to_enable);
534        miVec = 0; enabled = 0;
535        done = 0; new_entry = 0;
536    }
537    else {  // else every MI is enabled update state and return result to caller
538        vector<bool> successful(miVec->size());
539        for(u_int j=0; j < successful.size(); j++){
540            if((*miVec)[j]) successful[j] = true;
541            else successful[j] = false;
542        }
543        DMenableResponse(*new_entry,successful);
544    }
545    delete request;
546 }
547
548 // Tempest, get the bounds of the memory resource selected
549 string unslash(char *s)
550 {
551         string ret ;
552         char *p = strtok(s, "/") ;
553         while (p) {
554                 ret += p ;
555                 p = strtok(NULL, "/") ;
556         }
557         return ret ;
558 }
559 void dataManager::getMemoryBounds(perfStreamHandle,
560                                   vector<metric_focus_pair> *request)
561 {
562         dictionary_hash<string, unsigned> upper(string::hash) ;
563         dictionary_hash<string, unsigned> lower(string::hash) ;
564
565         for(unsigned j=0; request && (j < request->size()) ; j++)
566         {
567                 metricHandle  met =  ((*request)[j]).met ;
568                 string unique_name ;
569                 const char *metric_name = getMetricName(met) ;
570                 if(!metric_name)
571                 {
572                         cerr << "something is caught wrong by getMemoryBounds:"
573                              << "metricHandle =" << met 
574                              << "could be greater than metrics.size()"
575                              << " some thing is wrong!"
576                              << endl ;
577                         continue ;
578                 }
579                 unique_name += metric_name ;
580
581                 string Machine, Code, Process, SyncObject, Memory ;
582
583
584                 vector<resourceHandle> *res  = &((*request)[j].res) ;
585                 unsigned res_size = res->size() ;
586                 resourceHandle handle ;
587
588                 unsigned int min = 0 ; unsigned int max = 0 ; int yes = 0 ;
589                 for(unsigned i=0; i<res_size; i++)
590                 {
591                         handle = (*res)[i] ;
592                         resource *r = resource::resources[handle] ;
593                         const char *FullName = r->getFullName() ;
594                         char *temp = strdup(FullName) ;
595                         char *p = strchr(temp, '/')+1 ;
596
597                         switch(*p)
598                         {
599                         case 'M':
600                                 if(*(p+1)=='e')
601                                 {
602                                         char *blk = strrchr(p, '/') ;
603                                         if(blk && *(blk+1)>='0' && *(blk+1) <='9')
604                                         {
605                                                 blk++ ;
606                                                 yes = 1 ;
607                                                 Memory += "Memory" ;
608                                                 unsigned int addr = atoi(blk) ;
609                                                 if(min==0 || addr < min) min = addr ;
610                                                 if(addr > max)           max = addr ;
611                                                 p = NULL ;
612                                         }
613                                  }else
614                                         Machine += unslash(p);
615                                  break ;
616                         case 'P':
617                                 Process   += unslash(p);
618                                 break ;
619                         case 'S':
620                                 SyncObject += unslash(p) ;
621                                 break ;
622                         case 'C':
623                                 Code    += unslash(p) ;
624                         }
625                         free(temp) ;
626                 }
627                 if(yes)
628                 {
629                         unique_name += Machine;
630                         unique_name += Code;
631                         unique_name += Process;
632                         unique_name += SyncObject;
633                         unique_name += Memory;
634                         if(!upper.defines(unique_name) || max > upper[unique_name])
635                         {
636                                 upper[unique_name] = max ;
637                         }
638                         if(!lower.defines(unique_name) || min < lower[unique_name])
639                         {
640                                 lower[unique_name] = min ;
641                         }
642                 }
643         }
644         dictionary_hash_iter<string, unsigned> upper_iter(upper) ;
645         string flat ;
646         unsigned  u ;
647         // TO DO should I send a request to clear up
648         // current_upper_bounds and current_lower_bounds?
649         // I need to think about it more
650         while(upper_iter.next(flat, u))
651         {
652                 int l= lower[flat] ;
653                 printf("%s, %d->%d\n", flat.string_of(), l, u) ;
654                 for(unsigned j=0; j < paradynDaemon::allDaemons.size(); j++){
655                         paradynDaemon *pd = paradynDaemon::allDaemons[j];
656                         pd->memoryRangeSelected(flat, l, u) ;
657                 }
658         }
659
660 }
661
662
663 //
664 // Request to enable a set of metric/focus pairs
665 // ps_handle - the perfStreamHandle of the calling thread
666 // pt_handle - the perfTraceStreamHandle of the calling thread
667 // request   - vector of metic/focus pairs to enable
668 // request_Id - identifier passed by calling thread
669 // type - which phase type to enable data for
670 // phaseId - the identifier of the phase for which data is requested
671 // persistent_data - if set data is not distroyed on last disable 
672 // persistent_collection - if set data collection isn't stoped on disable 
673 // phase_persistent_data - like persistent_data, but only valid for curr
674 //                         phase
675 //
676 void dataManager::enableDataRequest(perfStreamHandle ps_handle,
677                                     perfStreamHandle pt_handle,
678                                     vector<metric_focus_pair> *request,
679                                     u_int request_Id,
680                                     phaseType type,
681                                     phaseHandle phaseId,
682                                     u_int persistent_data,
683                                     u_int persistent_collection,
684                                     u_int phase_persistent_data){
685
686     if((type == CurrentPhase) && (phaseId != phaseInfo::CurrentPhaseHandle())){
687         // send enable failed response to calling thread
688         vector<metricInstInfo> *response = 
689                                    new vector<metricInstInfo>(request->size());
690         for(u_int i=0; i < response->size();i++){
691             (*response)[i].successfully_enabled = false;            
692         }
693         // make response call
694         dictionary_hash_iter<perfStreamHandle,performanceStream*>
695                 allS(performanceStream::allStreams);
696         perfStreamHandle h; performanceStream *ps;
697         while(allS.next(h,ps)){
698             if(h == (perfStreamHandle)(ps_handle)){
699                 ps->callDataEnableFunc(response,request_Id);
700                 break;
701         } }
702         // trace data streams
703         allS.reset();
704         while(allS.next(h,ps)){
705             if(h == (perfStreamHandle)(pt_handle)){
706                 ps->callDataEnableFunc(response,request_Id);
707                 break;
708         }}
709         delete request;
710         response = 0;
711         return;
712     }
713
714     // convert request to vector of metricRLType
715     vector<metricRLType> *pairList = new vector<metricRLType>;
716     for(u_int i=0; i < request->size(); i++){
717         metricRLType newPair((*request)[i].met,
718                             resourceList::getResourceList((*request)[i].res)); 
719         *pairList += newPair; 
720     }
721     assert(request->size() == pairList->size());
722
723     DMdoEnableData(ps_handle,pt_handle,pairList,request_Id,type,phaseId,
724                   persistent_data,persistent_collection,phase_persistent_data);
725     delete request;
726     pairList = 0;
727 }
728
729 //
730 // same as enableDataRequest but with diff type for request 
731 //
732 void dataManager::enableDataRequest2(perfStreamHandle ps,
733                                      vector<metricRLType> *request,
734                                      u_int request_Id,
735                                      phaseType type,
736                                      phaseHandle phaseId,
737                                      u_int persistent_data,
738                                      u_int persistent_collection,
739                                      u_int phase_persistent_data){
740
741     // if currphase and phaseId != currentPhaseId then make approp.
742     // response call to client
743     if((type == CurrentPhase) && (phaseId != phaseInfo::CurrentPhaseHandle())){
744         // send enable failed response to calling thread
745         vector<metricInstInfo> *response = 
746                                    new vector<metricInstInfo>(request->size());
747         for(u_int i=0; i < response->size();i++){
748             (*response)[i].successfully_enabled = false;            
749         }
750         // make response call
751         dictionary_hash_iter<perfStreamHandle,performanceStream*>
752                 allS(performanceStream::allStreams);
753         perfStreamHandle h; performanceStream *ps;
754         while(allS.next(h,ps)){
755             if(h == (perfStreamHandle)(ps)){
756                 ps->callDataEnableFunc(response,request_Id);
757                 break;
758         } }
759         delete request;
760         response = 0;
761         return;
762       }
763
764     // 0 is used as the second parameter for non-trace use
765     DMdoEnableData(ps,0,request,request_Id,type,phaseId, persistent_data,
766                    persistent_collection,phase_persistent_data);    
767     
768 }
769
770
771 // data is really disabled when there are no current or global users and
772 // when the persistent_collection flag is clear
773 // when persistent_data flag is clear:
774 // current histogram is destroyed when there are no curr users 
775 // global histogram is destroyed whern there are no curr or gloabl users
776 // clear active flag on archived histograms rather than deleting them
777 void DMdisableRoutine(perfStreamHandle handle, 
778                       perfStreamHandle pt_handle,
779                       metricInstanceHandle mh, 
780                       phaseType type)
781 {
782
783     metricInstance *mi = metricInstance::getMI(mh);
784     if (!mi) return;
785
786     // if this mi is not enabled and there are no outstanding enable
787     // requests then ignore this disable  
788     if(!mi->isEnabled() && 
789        !mi->isGlobalEnableOutstanding() && 
790        !mi->isCurrEnableOutstanding()) return;
791
792     u_int num_curr_users = mi->currUsersCount();
793
794     // remove user from appropriate list
795     if (type == CurrentPhase) {
796         mi->removeCurrUser(handle); 
797     }
798     else {
799         mi->removeGlobalUser(handle);
800     }
801
802     // trace data streams
803     mi->removeTraceUser(pt_handle);
804
805     if (mi->isCollectionPersistent()) {
806         // just remove handle from appropriate client list and return
807         return;
808     }
809
810     // really disable MI data collection?  
811     // really disable data when there are no subscribers and
812     // there are no outstanding global or curr enables for this MI      
813     if (!(mi->currUsersCount()) 
814         && !mi->isGlobalEnableOutstanding() 
815         && !mi->isCurrEnableOutstanding()) {
816
817         u_int num_curr_hists = metricInstance::numCurrHists();
818         if (!(mi->isDataPersistent()) && !(mi->isPhaseDataPersistent())){
819             // remove histogram
820             if(mi->deleteCurrHistogram()){
821                 assert(metricInstance::numCurrHists());
822                 metricInstance::decrNumCurrHists();
823             }
824         }
825         else {  // clear active flag on current phase histogram
826             if(mi->data) {
827                 mi->data->clearActive();
828                 mi->data->setFoldOnInactive();
829                 if(num_curr_users){
830                     assert(metricInstance::numCurrHists());
831                     metricInstance::decrNumCurrHists();
832                 }
833         }}
834
835         if (!(mi->globalUsersCount())&& !mi->isGlobalEnableOutstanding()) {
836             mi->dataDisable();  // makes disable call to daemons
837             if (!(mi->isDataPersistent()) && !(mi->isPhaseDataPersistent())){
838                 delete mi;      
839                 mi = 0;
840                 assert(metricInstance::numGlobalHists());
841                 metricInstance::decrNumGlobalHists();
842             }
843             else {
844                 if(mi->global_data) {
845                     mi->global_data->clearActive();
846                     mi->global_data->setFoldOnInactive();
847                     assert(metricInstance::numGlobalHists());
848                     metricInstance::decrNumGlobalHists();
849             }}
850         }
851
852         // if this was last curr histogram then set sampling rate to global
853         if((num_curr_hists) && 
854            (!metricInstance::numCurrHists()) &&  
855            (metricInstance::numGlobalHists())){
856
857             float rate = Histogram::getGlobalBucketWidth();
858             newSampleRate(rate);
859         }
860     }
861     return;
862 }
863
864 // data is really disabled when there are no current or global users and
865 // when the persistent_collection flag is clear
866 // when persistent_data and phase_persistent_data flags are clear:
867 // current histogram is destroyed when there are no curr users 
868 // global histogram is destroyed whern there are no curr or gloabl users
869 // clear active flag on archived histograms rather than deleting them
870 void dataManager::disableDataCollection(perfStreamHandle handle, 
871                                         perfStreamHandle pt_handle,
872                                         metricInstanceHandle mh,
873                                         phaseType type) {
874
875     DMdisableRoutine(handle,pt_handle, mh,type);
876 }
877
878 //
879 // stop collecting data for the named metricInstance and clear the
880 // persistent data flag(s)
881 // ps_handle - a handle returned by createPerformanceStream
882 // mi_handle - a metricInstance returned by enableDataCollection.
883 // p_type - specifies either global or current phase data
884 // clear_persistent_data - if true, clear persistent_data flag before disabling
885 // clear_phase_persistent_data - if true, clear phase_persistent_data flag
886 //
887 void dataManager::disableDataAndClearPersistentData(perfStreamHandle ps_handle,
888                                         perfStreamHandle pt_handle,
889                                         metricInstanceHandle mi_handle,
890                                         phaseType p_type,
891                                         bool clear_persistent_data,
892                                         bool clear_phase_persistent_data) {
893
894     metricInstance *mi = metricInstance::getMI(mi_handle);
895     if (!mi) return;
896     if(clear_phase_persistent_data) mi->clearPhasePersistentData();
897     if(clear_persistent_data) mi->clearPersistentData();
898     DMdisableRoutine(ps_handle,pt_handle, mi_handle,p_type);
899 }
900
901 //
902 // This routine returns a list of foci which are the result of combining
903 // each child of resource rh with the remaining resources that make up rlh
904 // if the resource rh is a component of the focus rlh, otherwise it returns 0
905 //
906 vector<rlNameId> *dataManager::magnify(resourceHandle rh, 
907                                        resourceListHandle rlh){
908   
909 #ifdef PCDEBUG
910   printf("Call made to datamanager:magnify, which is calling resourceList::magnify(rh, eCallGraph)\n");
911 #endif
912
913     resourceList *rl = resourceList::getFocus(rlh);
914     if(rl){
915       //return(rl->magnify(rh, eCallGraph));
916       return(rl->magnify(rh, eOriginal));
917     }
918     return 0;
919 }
920
921
922 //
923 // This routine returns a list of foci each of which is the result of combining
924 // a child of one of the resources with the remaining resource components of
925 // rlh, this routine returns 0 if no resource components of rlh have children
926 // The DM allocates the vector, the client is responsible for deallocation
927 //
928 vector<rlNameId> *dataManager::magnify2(resourceListHandle rlh){
929     resourceList *rl = resourceList::getFocus(rlh);
930     if(rl){
931       //return (rl->magnify(eCallGraph));
932       return (rl->magnify(eOriginal));
933     }
934     return 0;
935 }
936
937
938 //
939 // if resource rh is a decendent of a component of the focus, return a new
940 // focus consisting of rh replaced with it's corresponding entry in rlh,
941 // otherwise return the focus rlh
942 //
943 resourceListHandle *dataManager::constrain(resourceHandle rh,
944                                           resourceListHandle rlh){
945     resourceList *rl = resourceList::getFocus(rlh);
946     if (rl) {
947          resourceListHandle *return_handle = rl->constrain(rh);
948         if(return_handle){
949             return return_handle;
950         }
951     }
952     resourceListHandle *default_handle = new resourceListHandle;
953     *default_handle = rlh;
954     return default_handle;
955 }
956
957 //
958 // like constrain, except it returns 0 on failure
959 //
960 resourceListHandle *dataManager::morespecific(resourceHandle rh,
961                                               resourceListHandle rlh){
962     resourceList *rl = resourceList::getFocus(rlh);
963     if (rl) {
964         return(rl->constrain(rh));
965     }
966     return 0;
967 }
968
969 //
970 // returns true if seppressSearch is true for this focus
971 //
972 bool dataManager::isSuppressed(resourceListHandle rlh){
973
974     resourceList *rl = resourceList::getFocus(rlh);
975     if (rl) {
976         return(rl->isSuppressed());
977     }
978     return 0;
979 }
980
981 //
982 // returns the name for the focus associated with this MI
983 // returns 0 on error
984 //
985 const char *dataManager::getFocusNameFromMI(metricInstanceHandle mh){
986     metricInstance *mi = metricInstance::getMI(mh);
987     if(mi){ 
988         return resourceList::getName(mi->getFocusHandle()); 
989     }
990     return 0;
991 }
992
993 //
994 // setting and clearing persistentCollection or persistentData flags
995 // have no enable/disable side effects 
996 //
997 void dataManager::setPersistentCollection(metricInstanceHandle mh){
998     metricInstance *mi = metricInstance::getMI(mh);
999     if(!mi) return;
1000     mi->setPersistentCollection();
1001 }
1002 void dataManager::clearPersistentCollection(metricInstanceHandle mh){
1003     metricInstance *mi = metricInstance::getMI(mh);
1004     if(!mi) return;
1005     mi->clearPersistentCollection();
1006 }
1007 void dataManager::setPersistentData(metricInstanceHandle mh){
1008     metricInstance *mi = metricInstance::getMI(mh);
1009     if(!mi) return;
1010     mi->setPersistentData();
1011
1012 }
1013
1014 //
1015 // clears both phase_persistent_data flag and persistent data flag
1016 // this routine may result in the MI being deleted
1017 //
1018 void dataManager::clearPersistentData(metricInstanceHandle mh){
1019     metricInstance *mi = metricInstance::getMI(mh);
1020     if(!mi) return;
1021     mi->clearPhasePersistentData();
1022     if(mi->clearPersistentData()) delete mi;
1023 }
1024
1025 metricHandle *dataManager::getMetric(metricInstanceHandle mh)
1026 {
1027     metricInstance *mi = metricInstance::getMI(mh);
1028     if(!mi) return 0;
1029
1030     metricHandle *handle = new metricHandle;
1031     *handle = mi->getMetricHandle();
1032     return(handle);
1033 }
1034
1035 const char *dataManager::getMetricNameFromMI(metricInstanceHandle mh)
1036 {
1037     metricInstance *mi = metricInstance::getMI(mh);
1038     if(mi){ 
1039         return(metric::getName(mi->getMetricHandle()));
1040     }
1041     return 0;
1042 }
1043
1044 const char *dataManager::getMetricName(metricHandle m)
1045 {
1046     const char *name = (metric::getName(m));
1047     if(name)
1048         return(name);
1049     return 0;
1050 }
1051
1052 sampleValue dataManager::getMetricValue(metricInstanceHandle mh)
1053 {
1054     metricInstance *mi = metricInstance::getMI(mh);
1055     if(mi) 
1056         return(mi->getValue());
1057     float ret = PARADYN_NaN;
1058     return(ret);
1059 }
1060
1061 sampleValue dataManager::getTotValue(metricInstanceHandle mh)
1062 {
1063     metricInstance *mi = metricInstance::getMI(mh);
1064     if(mi) 
1065         return(mi->getTotValue());
1066     float ret = PARADYN_NaN;
1067     return(ret);
1068 }
1069
1070 //
1071 // converts from a vector of resourceHandles to a resourceListHandle
1072 //
1073 resourceListHandle dataManager::getResourceList(const vector<resourceHandle> *h)
1074 {
1075   
1076     resourceListHandle r = resourceList::getResourceList(*h);
1077     return r;
1078 }
1079
1080 //
1081 // returns the corresponding focus name for a given resourceHandle vector
1082 //
1083 const char *dataManager::getFocusName(const vector<resourceHandle> *rh)
1084 {
1085   resourceListHandle rlh = resourceList::getResourceList(*rh);
1086   resourceList *rl = resourceList::getFocus(rlh);
1087   if (rl) 
1088     return(rl->getName());
1089   return 0;
1090 }
1091
1092 //
1093 // returns the name for the focus associated with this handle
1094 // returns 0 on error
1095 //
1096 const char *dataManager::getFocusNameFromHandle(resourceListHandle rlh){
1097   return resourceList::getName(rlh); 
1098 }
1099
1100
1101 //
1102 // converts from a resourceListHandle to a vector of resourceHandles
1103 //
1104 vector<resourceHandle> *dataManager::getResourceHandles(resourceListHandle h)
1105 {
1106     return resourceList::getResourceHandles(h);
1107 }
1108
1109 //
1110 // converts from a resource name to a resourceHandle
1111 //
1112 resourceHandle *dataManager::findResource(const char *name){
1113
1114     resourceHandle *rl = new resourceHandle;
1115     string r_name = name;
1116     if(resource::string_to_handle(r_name,rl)){
1117         return(rl);
1118     }
1119     return 0;
1120 }
1121
1122 //
1123 // returns name of resource (this is not a unique representation of 
1124 // the name instead it is the unique name trunctated)
1125 // so for "/Code/blah.c/foo" this routine will return "foo"
1126 //
1127 const char *dataManager::getResourceLabelName(resourceHandle h){
1128
1129      const char *s = resource::getName(h);
1130      if(s){
1131          return(s);
1132      }
1133      return 0;
1134 }
1135
1136 //
1137 // returns full name of resource ie.  "/Code/blah.c/foo"
1138 //
1139 const char *dataManager::getResourceName(resourceHandle h){
1140
1141      const char *s = resource::getFullName(h);
1142      if(s){
1143          return(s);
1144      }
1145      return 0;
1146 }
1147
1148 //
1149 // converts from a focus name to a resourceListHandle
1150 //
1151 resourceListHandle *dataManager::findResourceList(const char *name){
1152
1153     string n = name;
1154     const resourceListHandle *temp = resourceList::find(n);
1155     if(temp){
1156         resourceListHandle *h = new resourceListHandle;
1157         *h = *temp;
1158         return(h);
1159     }
1160     return 0;
1161 }
1162
1163
1164 void dataManager::getPredictedDataCost(perfStreamHandle ps_handle,
1165                                        metricHandle m_handle,
1166                                        resourceListHandle rl_handle,
1167                                        u_int clientId)
1168 {
1169     metric *m = metric::getMetric(m_handle);
1170     resourceList *rl = resourceList::getFocus(rl_handle);
1171     if(m && rl){
1172         paradynDaemon::getPredictedDataCostCall(ps_handle,m_handle,
1173                                                 rl_handle,rl,m,clientId);
1174     }
1175     else {
1176       cerr << "Error in DMpublic.C, m=NULL\n";
1177       assert(0);
1178     }
1179 }
1180
1181 // caller provides array of sampleValue to be filled
1182 // returns number of buckets filled
1183 int dataManager::getSampleValues(metricInstanceHandle mh,
1184                                  sampleValue *buckets,
1185                                  int numberOfBuckets,
1186                                  int first,
1187                                  phaseType phase)
1188 {
1189     metricInstance *mi = metricInstance::getMI(mh);
1190     if(mi) 
1191         return(mi->getSampleValues(buckets, numberOfBuckets, first, phase));
1192     return(0); 
1193 }
1194
1195
1196 // fill the passed array of buckets with the archived histogram values
1197 // of the passed metricInstance
1198 // returns number of buckets filled
1199 int dataManager::getArchiveValues(metricInstanceHandle mh,
1200                      sampleValue *buckets,
1201                      int numberOfBuckets,
1202                      int first,
1203                      phaseHandle phase_id){
1204
1205     metricInstance *mi = metricInstance::getMI(mh);
1206     if(mi) 
1207         return(mi->getArchiveValues(buckets, numberOfBuckets, first, phase_id));
1208     return 0;
1209 }
1210
1211
1212 void dataManager::printResources()
1213 {
1214     printAllResources();
1215 }
1216
1217 void dataManager::printStatus()
1218 {
1219     paradynDaemon::printStatus();
1220 }
1221
1222 void dataManager::coreProcess(int pid)
1223 {
1224     paradynDaemon::dumpCore(pid);
1225 }
1226
1227 void dataManager::StartPhase(timeStamp start_Time, 
1228                              const char *name,
1229                              bool with_new_pc,
1230                              bool with_visis)
1231 {
1232     string n = name;
1233     phaseInfo::startPhase(start_Time,n,with_new_pc,with_visis);
1234     // change the sampling rate
1235     if(metricInstance::numCurrHists()){
1236        // set sampling rate to curr phase histogram bucket width 
1237        float rate = phaseInfo::GetLastBucketWidth();
1238        newSampleRate(rate);
1239     }
1240     else {
1241        // set sampling rate to global phase histogram bucket width 
1242        float rate = Histogram::getGlobalBucketWidth();
1243        newSampleRate(rate);
1244     }
1245 }
1246
1247 vector<T_visi::phase_info> *dataManager::getAllPhaseInfo(){
1248     return(phaseInfo::GetAllPhaseInfo());
1249 }
1250
1251 //
1252 // Now for the upcalls.  We provide code that get called in the thread that
1253 //   requested the call back.
1254 //
1255 void dataManagerUser::newMetricDefined(metricInfoCallback cb,
1256                                   perfStreamHandle p_handle,
1257                                   const char *name,
1258                                   int style,
1259                                   int aggregate,
1260                                   const char *units,
1261                                   metricHandle handle,
1262                                   dm_MetUnitsType units_type)
1263 {
1264     
1265     (cb)(p_handle, name, style, aggregate, units, handle, units_type);
1266 }
1267
1268 void dataManagerUser::newResourceDefined(resourceInfoCallback cb,
1269                                          perfStreamHandle handle,
1270                                          resourceHandle parent,
1271                                          resourceHandle newResource,
1272                                          const char *name,
1273                                          const char *abstr)
1274 {
1275     (cb)(handle, parent, newResource, name, abstr);
1276 }
1277
1278 void dataManagerUser::newMemoryDefined(memoryInfoCallback cb,
1279                                         perfStreamHandle handle,
1280                                         const char *data_structure,
1281                                         int start,
1282                                         unsigned mem_size,
1283                                         unsigned blk_size,
1284                                         resourceHandle p_handle,
1285                                         vector<resourceHandle> *handles)
1286 {
1287     (cb)(handle, data_structure, start, mem_size, blk_size, p_handle, handles) ;
1288 }
1289
1290 void dataManagerUser::changeResourceBatchMode(resourceBatchModeCallback cb,
1291                                          perfStreamHandle handle,
1292                                          batchMode mode)
1293 {
1294     (cb)(handle, mode);
1295 }
1296
1297 //
1298 // response to enableDataRequest call
1299 // func - callback function registered by client thread on createPerfStream
1300 // response - vector of enable reponses to enable
1301 // request_id - identifier passed by client to enableDataRequest
1302 //
1303 void dataManagerUser::enableDataCallback(enableDataCallbackFunc func,
1304                                          vector<metricInstInfo> *response,
1305                                          u_int request_id)
1306 {
1307     (func)(response, request_id);
1308 }
1309
1310
1311 void dataManagerUser::histFold(histFoldCallback cb,
1312                                perfStreamHandle handle,
1313                                timeStamp width,
1314                                phaseType phase_type)
1315 {
1316     (cb)(handle, width, phase_type);
1317 }
1318
1319 void dataManagerUser::changeState(appStateChangeCallback cb,
1320                                   perfStreamHandle handle,
1321                                   appState state)
1322 {
1323     (cb)(handle, state);
1324 }
1325
1326 void dataManagerUser::newPerfData(sampleDataCallbackFunc func, 
1327                                   vector<dataValueType> *data,
1328                                   u_int num_data_values){
1329
1330     (func)(data, num_data_values);
1331 }
1332
1333 // trace data streams
1334 void dataManagerUser::newTracePerfData(traceDataCallbackFunc func,
1335                                   vector<traceDataValueType> *traceData,
1336                                   u_int num_traceData_values){
1337
1338     (func)(0, 0, 0.0, num_traceData_values,traceData);
1339 }
1340
1341 void dataManagerUser::predictedDataCost(predDataCostCallbackFunc func, 
1342                                   metricHandle,
1343                                   resourceListHandle,
1344                                   float cost,
1345                                   u_int clientID){
1346
1347     (func)(clientID, cost);
1348 }
1349
1350 void dataManagerUser::newPhaseInfo(newPhaseCallback cb,
1351                                    perfStreamHandle handle,
1352                                    const char *name,
1353                                    phaseHandle phase,
1354                                    timeStamp begin,
1355                                    timeStamp end,
1356                                    float bucketwidth,
1357                                    bool with_new_pc,
1358                                    bool with_visis) {
1359
1360     (cb)(handle,name,phase,begin,end,bucketwidth,with_new_pc,with_visis);
1361 }
1362
1363
1364 T_dyninstRPC::metricInfo *dataManager::getMetricInfo(metricHandle m_handle) {
1365
1366     const T_dyninstRPC::metricInfo *met = metric::getInfo(m_handle);
1367     if(met){ 
1368         T_dyninstRPC::metricInfo *copy = new T_dyninstRPC::metricInfo;
1369         copy->style = met->style;
1370         copy->units = met->units;
1371         copy->name = met->name;
1372         copy->aggregate = met->aggregate;
1373         copy->handle = met->handle;
1374         copy->unitstype = met->unitstype;
1375         return(copy);
1376     }
1377     return 0;
1378 }
1379
1380 #ifdef n_def
1381 resourceHandle dataManager::newResource(resourceHandle parent, 
1382                                         const char *newResource) {
1383     // rbi: kludge 
1384     // calls to this method should specify an abstraction,
1385     // but that involves a bunch of other changes that I don't want 
1386     // to make right now.
1387     // the kludge works because we know that all calls to this method 
1388     // are for BASE abstraction resources.  
1389
1390     // TEMP: until this routine is called with vector of strings for new res
1391     string res = resource::resources[parent]->getFullName();
1392     res += string("/");
1393     res += string(newResource);
1394     char *word = strdup(res.string_of());
1395     string next;
1396     vector<string> temp;
1397     unsigned j=1;
1398     for(unsigned i=1; i < res.length(); i++){
1399         if(word[i] == '/'){
1400             word[i] = '\0';
1401             next = &word[j];
1402             temp += next;
1403             j = i+1;
1404         }
1405     }
1406     next = &word[j];
1407     temp += next;
1408     string base = string("BASE");
1409     resourceHandle r = createResource(parent, temp, res, base);  
1410     paradynDaemon::tellDaemonsOfResource(res.string_of(),newResource);
1411     return(r);
1412 }
1413 #endif
1414
1415 resourceHandle dataManager::newResource(resourceHandle parent,
1416                                         const char *name, u_int type)
1417 {
1418
1419     // rbi: kludge
1420     // calls to this method should specify an abstraction,
1421     // but that involves a bunch of other changes that I don't want
1422     // to make right now.
1423     // the kludge works because we know that all calls to this method
1424     // are for BASE abstraction resources.
1425     
1426     string abs = "BASE";
1427     resource *parent_res = resource::handle_to_resource(parent);
1428     vector<string> res_name = parent_res->getParts();
1429     res_name += name;
1430     resourceHandle child = createResource(0,res_name,abs, type);
1431     paradynDaemon::tellDaemonsOfResource(parent_res->getHandle(), 
1432                                          child, 
1433                                          name, type);
1434     return(child);
1435
1436 }
1437
1438 timeStamp dataManager::getGlobalBucketWidth()
1439 {
1440     return(Histogram::getGlobalBucketWidth());
1441 }
1442
1443 timeStamp dataManager::getCurrentBucketWidth()
1444 {
1445     return(phaseInfo::GetLastBucketWidth());
1446 }
1447
1448 timeStamp dataManager::getCurrentStartTime() 
1449 {
1450     return(phaseInfo::GetLastPhaseStart());
1451 }
1452
1453 u_int dataManager::getCurrentPhaseId() 
1454 {
1455     return(phaseInfo::CurrentPhaseHandle());
1456 }
1457
1458
1459
1460 int dataManager::getMaxBins()
1461 {
1462     return(Histogram::getNumBins());
1463 }
1464
1465 void dataManager::printDaemons()
1466 {
1467   paradynDaemon::printDaemons();
1468 }
1469
1470 vector<string> *dataManager::getAvailableDaemons()
1471 {
1472     return(paradynDaemon::getAvailableDaemons());
1473 }