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