startTime() --> firstTimeAndValue()
[dyninst.git] / paradynd / src / costmetrics.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 #include "paradynd/src/costmetrics.h"
43 #include "dyninstAPI/src/process.h"
44
45 vector<costMetric*> costMetric::allCostMetrics;
46 extern vector<process*> processVec;
47
48 costMetric::costMetric(const string n,
49                      metricStyle style,
50                      int a,
51                      const string units,
52                      im_pred_struct& preds,
53                      bool developerMode,
54                      daemon_MetUnitsType unitstype,
55                      int combiner_op): 
56    aggSample((combiner_op != -1) ? combiner_op : a)
57 {
58
59    name_ = n; style_ = style; agg_ = a; units_ = units; pred = preds; 
60    developermode_ = developerMode; unitstype_ = unitstype;
61    node = 0; past_head = 0; smooth_sample = 0.0;
62    if((combiner_op >= 0) && (combiner_op <= 3)) 
63        combinerop_ = combiner_op;
64    else combinerop_ = -1;
65
66    for(unsigned i = 0; i < PAST_LIMIT; i++){
67        past[i].value = -1.0;
68        past[i].len = 0.0;
69    }
70
71    for(unsigned i2 = 0; i2 < processVec.size(); i2++){
72        if((processVec[i2])->status_ != exited){
73            components += processVec[i2];
74            //sampleInfo *s = new sampleInfo;
75            sampleInfo *s = aggSample.newComponent();
76            parts += s;
77            lastProcessTime += 0.0; 
78            cumulative_values += 0.0;
79        }
80    }
81 }
82
83
84 costMetric *costMetric::newCostMetric(const string n,
85                                      metricStyle style,
86                                      int a,
87                                      const string units,
88                                      im_pred_struct& preds,
89                                      bool developerMode,
90                                      daemon_MetUnitsType unitstype,
91                                      int combiner_op){
92
93
94     costMetric *newcm = new costMetric(n,style,a,units,preds,
95                                       developerMode,unitstype,combiner_op);
96     allCostMetrics += newcm; 
97     return newcm;
98 }
99
100
101 bool costMetric::legalToInst(vector< vector<string> >& focus) {
102
103     if (!processVec.size()) {
104         // we don't enable metrics if there are no process to run
105         return false;
106     }
107
108     bool all_exited = true;
109     for(u_int i=0; i < processVec.size(); i++){
110         if((processVec[i])->status_ != exited){
111             all_exited = false;
112     } }
113     if(all_exited) return false;
114
115     switch (focus[resource::machine].size()) {
116         case 1: break;
117         case 2:
118             switch(pred.machine) {
119                 case pred_invalid: return false;
120                 case pred_null: break;
121                 default: return false;
122             }
123         default: return false;
124     }
125     switch (focus[resource::procedure].size()) {
126         case 1: break;
127         case 2:
128         case 3:
129             switch(pred.procedure) {
130                 case pred_invalid: return false;
131                 case pred_null: break;
132                 default: return false;
133             }
134         default: return false;
135     }
136     switch (focus[resource::process].size()) {
137         case 1: break;
138         case 2:
139             switch(pred.process) {
140                 case pred_invalid: return false;
141                 case pred_null: break;
142                 default: return false;
143             }
144         default: return false;
145     }
146     switch (focus[resource::sync_object].size()) {
147         case 1: break;
148         case 2:
149         case 3:
150             switch(pred.sync) {
151                 case pred_invalid: return false;
152                 case pred_null: break;
153                 default: return false;
154             }
155         default: return false;
156     }
157     return true;
158 }
159
160 bool costMetric::addProcess(process *p){
161
162     for(unsigned i = 0; i < components.size(); i++){
163        if(p == components[i])
164          return false;
165     }
166     components += p;
167     sampleInfo *s = aggSample.newComponent();
168     parts += s;
169     lastProcessTime += 0.0;
170     cumulative_values += 0.0;
171     return true;
172 }
173
174 bool costMetric::removeProcess(process *p){
175     unsigned size = components.size();
176     for(unsigned i = 0; i < size; i++){
177        if(p == components[i]){
178            //sampleInfo *olddata = parts[i];
179            aggSample.removeComponent(parts[i]);
180            for(unsigned j = i; j < size-1; j++){
181                components[j] = components[j+1];
182                parts[j] = parts[j+1];
183                lastProcessTime[j] = lastProcessTime[j+1];
184                cumulative_values[j] = cumulative_values[j+1];
185            }
186            components.resize(size -1);
187            parts.resize(size -1);
188            lastProcessTime.resize(size -1);
189            cumulative_values.resize(size -1);
190            // delete olddata;
191            assert(components.size() == parts.size());
192            assert(lastProcessTime.size() == parts.size());
193            assert(cumulative_values.size() == parts.size());
194            return true;
195        }
196     }
197     return false;
198 }
199
200
201 bool costMetric::addProcessToAll(process *p){
202
203     for(unsigned i=0; i < allCostMetrics.size(); i++){
204         costMetric *next_met = allCostMetrics[i];
205         next_met->addProcess(p);
206     }
207     return true;
208 }
209
210 bool costMetric::removeProcessFromAll(process *p){
211     for(unsigned i=0; i < allCostMetrics.size(); i++){
212         costMetric *next_met = allCostMetrics[i];
213         next_met->removeProcess(p);
214     }
215     return true;
216 }
217
218
219 sampleInterval costMetricValueUpdate(costMetric *met,
220                                      process *proc,
221                                      sampleValue value,
222                                      timeStamp endTime,
223                                      timeStamp processTime){
224
225     sampleInterval ret;
226     ret.valid = false;
227     int proc_num = -1;
228     for(unsigned i=0; i < met->components.size(); i++){
229         if(proc == met->components[i]) proc_num = i;
230     }
231     if(proc_num == -1) return ret;
232
233     met->lastProcessTime[proc_num] = processTime;
234
235     // currently all cost metrics are EventCounters
236     if(met->style_ == EventCounter){
237         // only use delta from last sample
238         if (value < met->cumulative_values[proc_num]) {
239
240 #ifdef ndef
241             if ((value/met->cumulative_values[proc_num]) < 0.99999) {
242                 char buffer[200];
243                 sprintf(buffer,"value = %f cumulative_value = %f proc = %d met = %s\n",
244                         value,met->cumulative_values[proc_num],proc_num,
245                         met->getName());
246                 logLine(buffer);
247                 assert((value + 0.0001)  >= met->cumulative_values[proc_num]);
248             } else {
249                // floating point rounding error ignore
250                met->cumulative_values[proc_num] = value;
251             }
252 #endif
253             value = met->cumulative_values[proc_num];
254         }
255         value -= met->cumulative_values[proc_num];
256         met->cumulative_values[proc_num] += value;
257     }
258
259     // update the sample value associated with the process proc
260     if((met->parts[proc_num])->firstValueReceived()){
261         // ret = (met->parts[proc_num])->newValue(endTime,value);
262         (met->parts[proc_num])->newValue(endTime,value);
263     }
264     else {
265         // this is the first sample. Since we don't have the start time for this
266         // sample, we have to loose it, but we set the start time here.
267         // ret = (met->parts[proc_num])->startTime(endTime);
268         // (met->parts[proc_num])->value = value;
269
270 //        (met->parts[proc_num])->startTime(endTime);
271         (met->parts[proc_num])->firstTimeAndValue(endTime, value);
272     }
273     // update value if we have a new value from each part
274     // ret = met->sample.newValue(met->parts, endTime, value);
275     // if(ret.valid) met->sample.value = ret.value;
276     ret = met->aggSample.aggregateValues();
277     if(ret.valid) met->cumulativeValue = ret.value;
278     return ret;
279 }
280
281 void costMetric::updateValue(process *proc,
282                              sampleValue value,
283                              timeStamp endTime,
284                              timeStamp processTime){
285
286     sampleInterval ret = costMetricValueUpdate(this,proc,value,
287                                                endTime,processTime); 
288
289     if (node && ret.valid) {
290         // kludge to fix negative time from CM5 
291         if (ret.start < 0.0) ret.start = 0.0;
292         assert(ret.end >= 0.0);
293         assert(ret.end >= ret.start);
294         if (ret.end-ret.start-ret.value > 0) {
295             ret.value = (ret.end-ret.start)*(ret.end-ret.start)
296                 /(ret.end-ret.start-ret.value);
297             node->forwardSimpleValue(ret.start,ret.end,ret.value,1,true);
298         }
299     }
300 }
301
302
303 void costMetric::updateSmoothValue(process *proc,
304                              sampleValue newValue,
305                              timeStamp endTime,
306                              timeStamp processTime){
307
308     sampleInterval ret = costMetricValueUpdate(this,proc,newValue,
309                                                endTime,processTime); 
310
311     if(ret.valid){ // there is a new value for this interval
312         // compute smoothed value 
313         smooth_sample = 0.0;
314         timeStamp length = ret.end - ret.start;
315         if(length > 0.0){
316             float total_len = (float)length;
317             sampleValue temp = ret.value;
318             for(unsigned i=0; i < PAST_LIMIT; i++){
319                 if(past[i].value != -1.0){
320                     temp += past[i].value;      
321                     total_len += past[i].len;
322                 } 
323             }
324             smooth_sample = temp / (total_len);
325             // add new value to the past list
326             past[past_head].value = ret.value;  
327             past[past_head++].len = length;  
328             if(past_head >= PAST_LIMIT) past_head = 0;
329             // compute value for the appropriate time interval
330             smooth_sample *= length;
331             //sample.value = smooth_sample;
332             cumulativeValue = smooth_sample;
333         }
334         if(node){  // actually send the value
335             // kludge to fix negative time from CM5 
336             if (ret.start < 0.0) ret.start = 0.0;
337             assert(ret.end >= 0.0);
338             assert(ret.end >= ret.start);
339             if (ret.end-ret.start-ret.value > 0) {
340                 ret.value = (ret.end-ret.start)*(ret.end-ret.start)
341                     /(ret.end-ret.start-ret.value);
342                 node->forwardSimpleValue(ret.start,ret.end,smooth_sample,1,true);
343             }
344         }
345     }
346 }