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