added functionality for new Paradyn Save feature
[dyninst.git] / paradyn / src / DMthread / DMmetric.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 #include <stdio.h>
45 }
46 #include "DMmetric.h"
47 #include <iostream.h>
48
49 extern void histDataCallBack(sampleValue*, timeStamp, int, int, void*, bool);
50 extern void histFoldCallBack(timeStamp, void*, bool);
51
52 // trace data streams
53 extern void traceDataCallBack(void*, int, void*);
54
55 metric::metric(T_dyninstRPC::metricInfo i){
56
57     if(allMetrics.defines(i.name)) return;
58     info.style = i.style;
59     info.units = i.units;
60     info.name = i.name;
61     info.developerMode = i.developerMode;
62     info.unitstype = i.unitstype;
63     info.aggregate = i.aggregate;
64     info.handle = metrics.size();
65     metric *met = this;
66     allMetrics[i.name] = met;
67     metrics += met;
68 }
69
70 const T_dyninstRPC::metricInfo *metric::getInfo(metricHandle handle) { 
71    
72     if(handle < metrics.size()){
73         metric *met = metrics[handle];
74         return(met->getInfo());
75     }
76     else{
77         return 0 ;
78     }
79 }
80
81 const char *metric::getName(metricHandle handle){
82      if(handle < metrics.size()){
83         metric *met = metrics[handle];
84         return(met->info.name.string_of());
85      }
86      else{
87         return 0 ;
88      }
89 }
90
91 const metricHandle *metric::find(const string iName){ 
92      if(allMetrics.defines(iName)){
93         return(&(allMetrics[iName])->info.handle);
94      }
95      else{
96         return 0 ;
97      }
98 }
99
100 metric *metric::getMetric(metricHandle handle){ 
101      if(handle < metrics.size()){
102         return(metrics[handle]);
103      }
104      else{
105         return 0 ;
106      }
107 }
108
109 vector<string> *metric::allMetricNames(bool all){
110
111     vector<string> *temp = new vector<string>;
112     string name;
113     tunableBooleanConstant developerMode =
114                            tunableConstantRegistry::findBoolTunableConstant(
115                            "developerMode");
116     bool developerModeActive = developerMode.getValue();
117     for(unsigned i=0; i < metrics.size(); i++){
118         metric *met = metrics[i];
119         if (all || developerModeActive) {
120           string name = met->getName();
121           *temp += name;
122         }
123         else if (!met->isDeveloperMode()) {
124           string name = met->getName();
125           *temp += name;
126         }
127     }
128     return(temp);
129 }
130
131 vector<met_name_id> *metric::allMetricNamesIds(bool all){
132
133     vector<met_name_id> *temp = new vector<met_name_id>;
134     met_name_id next;
135     tunableBooleanConstant developerMode =
136                            tunableConstantRegistry::findBoolTunableConstant(
137                            "developerMode");
138     bool developerModeActive = developerMode.getValue();
139
140     for(unsigned i=0; i < metrics.size(); i++){
141         metric *met = metrics[i];
142         if (all || developerModeActive) {
143           next.name = met->getName();
144           next.id = met->getHandle();
145           *temp += next; 
146         }
147         else if (!met->isDeveloperMode()) {
148           next.name = met->getName();
149           next.id = met->getHandle();
150           *temp += next;
151         }
152     }
153     return(temp);
154 }
155
156 metricInstance::metricInstance(resourceListHandle rl, 
157                                metricHandle m,
158                                phaseHandle ph): 
159     aggSample((metric::getMetric(m)->getAggregate())) {
160     met = m;
161     focus = rl;
162     enabledTime = 0.0;
163     //metric *mp = metric::getMetric(m);
164     //sample.aggOp = mp->getAggregate();
165     data = 0;
166     global_data = 0;
167     persistent_data = false;
168     persistent_collection = false;
169     phase_persistent_data = false;
170     currEnablesWaiting = 0;
171     globalEnablesWaiting = 0;
172     enabled = false;
173     currently_enabling = false;
174     metricInstance::curr_phase_id = ph;
175     id = next_id++;
176     allMetricInstances[id] = this;
177
178     // trace data streams
179     traceFunc = 0;
180 }
181
182 metricInstance::~metricInstance() {
183     for(unsigned i=0; i < components.size(); i++){
184         delete (components[i]);    
185     }
186     // for(unsigned j=0; j < parts.size(); j++){
187     //        delete (parts[j]);    
188     // }
189     for(unsigned k=0; k < old_data.size(); k++){
190         delete (old_data[k]);    
191     }
192     if (data) delete(data);
193     if (global_data) delete(global_data);
194     // remove metricInstace from list of allMetricsInstances
195     allMetricInstances.undef(id);
196 }
197
198 int metricInstance::getArchiveValues(sampleValue *buckets,int numOfBuckets,
199                                     int first,phaseHandle phase_id){
200
201     // find histogram associated with phase_id
202     for(unsigned i = 0; i < old_data.size(); i++){
203         if((old_data[i])->phaseId == phase_id){
204             if((old_data[i])->data)
205                 return((old_data[i])->data->getBuckets(buckets,
206                                                        numOfBuckets,first));
207         }
208     }
209     return -1;
210 }
211
212 int metricInstance::getSampleValues(sampleValue *buckets,int numOfBuckets,
213                                     int first,phaseType phase){
214
215     if(phase == CurrentPhase){
216         if (!data) return (-1);
217         return(data->getBuckets(buckets, numOfBuckets, first));
218     }
219     else {
220         if (!global_data) return (-1);
221         return(global_data->getBuckets(buckets, numOfBuckets, first));
222     }
223
224 }
225
226 // 
227 // write out all data for a single histogram to specified file
228 // this routine assumes that fptr points to a valid file open for writing!  
229 //
230 void 
231 metricInstance::saveAllData (ofstream& fptr, phaseType ph)
232 {
233   // first locate the histogram
234   timeStamp width;
235   Histogram *hdata;
236   if (ph == GlobalPhase) {
237     hdata = global_data;
238     width = global_bucket_width;
239   } else {
240     hdata = data;
241     width = curr_bucket_width;
242   }
243   if (hdata == NULL)
244     // histogram not created yet for this MI
245     return;
246
247   string writeout;
248   int numBins = hdata->getNumBins();
249   sampleValue *buckets = new sampleValue [numBins];
250   unsigned count = hdata->getBuckets(buckets, numBins, 0);
251   // write header info:  numBuckets, bucketWidth
252   fptr << numBins << " " << width << endl;
253   // write all data values
254   for (unsigned k = 0; k < count; k++) {
255     fptr << string(buckets[k]) << endl;
256   }
257
258   if (ph == CurrentPhase) {
259     // save archived data, if any
260     for (unsigned i = 0; i < old_data.size(); i++) {
261       hdata = (old_data[i])->data;
262       if ( hdata ) {
263         count = hdata->getBuckets(buckets, numBins, 0);
264         // header info:  numBuckets, bucketWidth 
265         fptr << numBins << " " << width << endl;
266         // data
267         for (unsigned k = 0; k < count; k++) {
268           fptr << buckets[k] << endl;
269         }
270       }
271     }
272   }
273   delete buckets;
274 }
275
276
277 metricInstance *metricInstance::getMI(metricInstanceHandle mh){
278
279     metricInstance* mih;
280     bool found = allMetricInstances.find(mh, mih);
281     if (found) {
282         return mih;
283     }
284     return 0;
285 }
286
287 // TODO: remove asserts
288 void metricInstance::dataDisable(){
289     
290     assert(!users.size());
291     assert(!global_users.size());
292     for(unsigned i=0; i < components.size(); i++){
293         aggSample.removeComponent(components[i]->sample);
294         delete (components[i]);  // this disables data collection  
295     }
296     components.resize(0);
297     // deleteing components deletes parts as well
298     //    parts.resize(0);
299     //    num_procs_per_part.resize(0);
300     enabled = false;
301     // if data is persistent this must be cleared 
302     //    sample.firstSampleReceived = false;  
303     assert(!components.size());
304     //    assert(!parts.size());
305 }
306
307 void metricInstance::removeCurrUser(perfStreamHandle ps){
308
309     // remove ps from vector of users
310     unsigned size = users.size();
311     for(unsigned i=0; i < size; i++){
312         if(users[i] == ps){
313             users[i] = users[size-1];
314             users.resize(size-1);
315             assert(users.size() < size);
316             // decrease ps's data buffer size
317             performanceStream::removeCurrentUser(ps);
318             return;
319     } }
320 }
321
322 void metricInstance::removeGlobalUser(perfStreamHandle ps){
323
324     // remove ps from vector of users
325     unsigned size = global_users.size();
326     for(unsigned i=0; i < size; i++){
327         if(global_users[i] == ps){
328             global_users[i] = global_users[size-1];
329             global_users.resize(size-1);
330             assert(global_users.size() < size);
331             // decrease ps's data buffer size
332             performanceStream::removeGlobalUser(ps);
333             return;
334     } }
335 }
336
337 // trace data streams
338 void metricInstance::removeTraceUser(perfStreamHandle ps){
339
340     // remove ps from vector of users
341     unsigned size = trace_users.size();
342     for(unsigned i=0; i < size; i++){
343         if(trace_users[i] == ps){
344             trace_users[i] = trace_users[size-1];
345             trace_users.resize(size-1);
346             assert(trace_users.size() < size);
347             // decrease ps's data buffer size
348             performanceStream::removeTraceUser(ps);
349             return;
350     } }
351 }
352
353 // returns true if histogram really was deleted
354 bool metricInstance::deleteCurrHistogram(){
355
356     // if curr histogram exists and there are no users delete
357     if(!(users.size()) && data) {
358         delete data;
359         data = 0;
360         return true;
361     }
362     return false;
363 }
364
365 metricInstance *metricInstance::find(metricHandle mh, resourceListHandle rh){
366
367     
368     dictionary_hash_iter<metricInstanceHandle,metricInstance *> 
369                         allMI(allMetricInstances);
370     metricInstanceHandle handle;
371     metricInstance *mi;
372     while(allMI.next(handle,mi)){
373         if((mi->getMetricHandle() == mh) && (mi->getFocusHandle() == rh)){
374             return(mi);
375         }
376     }
377     return 0;
378 }
379
380 //
381 // clears the persistent_data flag and deletes any histograms without 
382 // subscribers.  The values for num_global_hists and num_curr_hists are
383 // not changed because these are for active histograms, and this routine
384 // should not delete any histograms that are active.
385 // returns true if the metric instance can be deleted
386 //
387 bool metricInstance::clearPersistentData(){
388   
389     phase_persistent_data = false;
390     // if there are no outstanding enables for this MI and the flag was set 
391     if(persistent_data && !globalEnablesWaiting && !currEnablesWaiting){ 
392        // if persistent collection is false then may need to delete data
393        if(!persistent_collection){
394            // if there are no current subscribers delete curr. hist and 
395            // archieved histograms
396            if(users.size() == 0){
397                if(data){
398                    delete data;
399                    data = 0;
400                }
401                // delete any archived histograms
402                for(unsigned k=0; k < old_data.size(); k++){
403                    delete (old_data[k]);    
404                    old_data.resize(0);
405                }
406            }
407            // if there are no curr. or global data subscribers and if
408            // persistent_collection is false then delete the metric instance
409            if(!enabled){
410                if((global_users.size() == 0) && global_data){ 
411                    delete global_data;
412                    global_data = 0;
413                    persistent_data = false;
414                    return true;
415                }
416            }
417        }
418     }
419     persistent_data = false;
420     return false;
421 }
422
423 bool metricInstance::addComponent(component *new_comp){
424
425     paradynDaemon *new_daemon =  new_comp->getDaemon();
426     for (unsigned i=0; i < components.size(); i++){
427          if((components[i])->getDaemon() == new_daemon) return false;
428     }
429     components += new_comp;
430     new_comp->sample = aggSample.newComponent();
431     return true;
432 }
433
434 // remove the component correspondent to daemon
435 // If there are no more componets, flush aggregate samples, 
436 // and notify clients.
437 bool metricInstance::removeComponent(paradynDaemon *daemon) {
438     unsigned size = components.size();
439     for (unsigned u = 0; u < size; u++) {
440       if (components[u]->getDaemon() == daemon) {
441         aggSample.removeComponent(components[u]->sample);
442         delete (components[u]);
443         if (u < size-1) {
444           components[u] = components[size-1];
445         }
446         components.resize(size-1);
447         if (size == 1) {
448           // the last component was removed
449           // flush aggregate samples
450           struct sampleInterval ret;
451           ret = aggSample.aggregateValues();
452           while (ret.valid) {
453             assert(ret.end >= 0.0);
454             assert(ret.start >= 0.0);
455             assert(ret.end >= ret.start);
456             enabledTime += ret.end - ret.start;
457             addInterval(ret.start, ret.end, ret.value, false);
458             ret = aggSample.aggregateValues();
459           }
460         }
461         return true;
462       }
463     }
464     return false;
465 }
466
467 #ifdef notdef
468 bool metricInstance::addPart(sampleInfo *new_part){
469     parts += new_part;
470     u_int new_size = num_procs_per_part.size() + 1;
471     num_procs_per_part.resize(new_size);
472     assert(parts.size() == num_procs_per_part.size());
473     return true;
474 }
475 #endif
476
477 // stops currentPhase data collection for all metricInstances
478 void metricInstance::stopAllCurrentDataCollection(phaseHandle last_phase_id) {
479
480     dictionary_hash_iter<metricInstanceHandle,metricInstance *> 
481                         allMI(allMetricInstances);
482     metricInstanceHandle handle;
483     metricInstance *mi;
484  
485     vector<metricInstance *> remove_list;
486     allMI.reset();
487     while(allMI.next(handle,mi)){
488         remove_list += mi;
489     }
490      
491     assert(remove_list.size() == allMetricInstances.size());
492     for(unsigned i=0; i < remove_list.size(); i++){
493         mi = remove_list[i];
494         mi->currEnablesWaiting = 0;
495         // remove all users from user list
496         mi->users.resize(0);
497         assert(!(mi->users.size()));
498         // clear the persistent flag that is only valid within a phase
499         mi->clearPhasePersistentData();
500
501         bool was_deleted = false;
502         // if persistent data archive curr histogram
503         if(mi->isDataPersistent()){
504             if (mi->data) {
505                 if(mi->data->isActive()) was_deleted = true;    
506                 mi->data->clearActive();
507                 mi->data->clearFoldOnInactive();
508                 ArchiveType *temp = new ArchiveType;
509                 temp->data = mi->data;
510                 temp->phaseId = last_phase_id; 
511                 mi->old_data += temp;
512                 mi->data = 0;
513                 temp = 0; 
514             }
515         }
516         else { // else delete curr histogram
517             was_deleted = mi->deleteCurrHistogram();
518         }
519
520
521         // if not persistent collection
522         if (!(mi->isCollectionPersistent())){
523             // really disable data collection 
524             if((mi->isEnabled()) && (!mi->globalUsersCount())) { 
525                 // disable MI data collection 
526                 mi->dataDisable();
527                 if(!(mi->isDataPersistent())){
528                     delete(mi);
529                 }
530                 metricInstance::decrNumGlobalHists();
531             }
532             if(was_deleted)
533                 metricInstance::decrNumCurrHists();
534         }
535         else { // else, create new curr histogram with empty curr users list
536             metric *m = metric::getMetric(mi->met);
537             mi->newCurrDataCollection(m->getStyle(),
538                                       histDataCallBack,
539                                       histFoldCallBack);
540         }
541     }
542     // reduce each performance stream's buffer size by the number
543     // of current MI's it will no longer be receiving data for
544     performanceStream::removeAllCurrUsers();
545 }
546
547
548 void metricInstance::addCurrentUser(perfStreamHandle p) {
549
550     for(unsigned i=0; i < users.size(); i++){
551         if(users[i] == p) return;
552     }
553     users += p;
554     assert(users.size());
555     // update buffersize for perfStream
556     performanceStream::addCurrentUser(p);
557 }
558
559 void metricInstance::addGlobalUser(perfStreamHandle p) {
560
561     for(unsigned i=0; i < global_users.size(); i++){
562         if(global_users[i] == p) return;
563     }
564     global_users += p;
565     assert(global_users.size());
566     // update buffersize for perfStream
567     performanceStream::addGlobalUser(p);
568 }
569
570 // trace data streams
571 void metricInstance::addTraceUser(perfStreamHandle p) {
572
573     for(unsigned i=0; i < trace_users.size(); i++){
574         if(trace_users[i] == p) return;
575     }
576     trace_users += p;
577     assert(trace_users.size());
578     // update buffersize for perfStream
579     performanceStream::addTraceUser(p);
580
581 }
582
583 // trace data streams
584 void metricInstance::newTraceDataCollection(dataCallBack2 dcb) {
585     assignTraceFunc(dcb);
586 }
587
588 void metricInstance::newGlobalDataCollection(metricStyle style, 
589                                              dataCallBack dcb, 
590                                              foldCallBack fcb) {
591
592     // histogram has already been created
593     if (global_data) {
594         global_data->setActive();
595         global_data->clearFoldOnInactive();
596         return;  
597     }
598     // call constructor for start time 0.0 
599     global_data = new Histogram(style, dcb, fcb, this, 1);
600 }
601
602 void metricInstance::newCurrDataCollection(metricStyle style, 
603                                            dataCallBack dcb, 
604                                            foldCallBack fcb) {
605
606     // histogram has already been created
607     if (data) {
608         data->setActive();
609         data->clearFoldOnInactive();
610         return;  
611     }
612     // create new histogram
613     timeStamp start_time = phaseInfo::GetLastPhaseStart();
614     if(start_time == 0.0) {
615         data = new Histogram(style, dcb, fcb, this, 0);
616         assert(data);
617         phaseInfo::setCurrentBucketWidth(data->getBucketWidth());
618
619     }
620     else {
621         data = new Histogram(start_time, style, dcb, fcb, this, 0);
622         assert(data);
623         phaseInfo::setCurrentBucketWidth(data->getBucketWidth());
624     }
625 }
626