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