removed a print stmt
[dyninst.git] / pdutil / src / aggregateSample.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 /*
43  * 
44  * $Log: aggregateSample.C,v $
45  * Revision 1.16  1997/10/08 18:27:59  tamches
46  * removed a print stmt
47  *
48  * Revision 1.15  1997/09/26 15:51:07  tamches
49  * startTime() --> firstTimeAndValue().
50  * newValue() now returns void
51  * Provided an int version of newValue()
52  *
53  * Revision 1.14  1996/08/16 21:31:50  tamches
54  * updated copyright for release 1.1
55  *
56  * Revision 1.13  1996/03/12 20:38:49  mjrg
57  * New version of aggregateSample to support adding and removing components
58  * dynamically.
59  *
60  * Revision 1.12  1996/02/09 22:15:28  mjrg
61  * fixed aggregation to handle first samples and addition of new components
62  *
63  * Revision 1.11  1996/01/31 19:47:37  newhall
64  * added a newValue method that takes a vector of weights for each part
65  *
66  * Revision 1.10  1995/09/08  19:44:56  krisna
67  * stupid way to avoid the for-scope problem
68  *
69  * Revision 1.9  1995/06/02  21:00:07  newhall
70  * added a NaN value generator
71  * fixed memory leaks in Histogram class
72  * added newValue member with a vector<sampleInfo *> to class sampleInfo
73  *
74  * Revision 1.8  1995/02/16  09:27:59  markc
75  * Removed compiler warnings.
76  * Changed Boolean to bool
77  *
78  */
79
80 #include <assert.h>
81 #include <math.h>
82
83 #include "util/h/aggregateSample.h"
84
85 // void sampleInfo::startTime(timeStamp time) {
86 //   assert(numAggregators > 0);
87 //   firstSampleReceived = true;
88 //   lastSampleStart = time;
89 //   // The remaining fields should be zero.
90 //   // It is important that the value of lastSampleEnd is zero, otherwise the
91 //   // aggregation code in newValue will not work.
92 // }
93
94 void sampleInfo::firstTimeAndValue(timeStamp time, int firstValue) {
95   assert(numAggregators > 0);
96   firstSampleReceived = true;
97   lastSampleStart = time;
98
99   assert(lastSample == 0);
100   lastSample = (sampleValue)firstValue; // yuck; we lose something in int-->float conversion
101   
102   // The remaining fields should be zero.
103   // It is important that the value of lastSampleEnd is zero, otherwise the
104   // aggregation code in newValue will not work.
105 }
106
107 void sampleInfo::firstTimeAndValue(timeStamp time, float firstValue) {
108   assert(numAggregators > 0);
109   firstSampleReceived = true;
110   lastSampleStart = time;
111
112   assert(lastSample == 0);
113   lastSample = firstValue;
114   
115   // The remaining fields should be zero.
116   // It is important that the value of lastSampleEnd is zero, otherwise the
117   // aggregation code in newValue will not work.
118 }
119
120 void sampleInfo::newValue(timeStamp sampleTime, 
121                           int newVal,
122                           unsigned weight_) {
123     assert(firstSampleReceived);
124     assert(sampleTime > lastSampleEnd);
125
126     // used when it's a component of an aggregate.
127     lastSample += newVal;
128     lastSampleEnd = sampleTime;
129     weight = weight_;
130 }
131
132 void sampleInfo::newValue(timeStamp sampleTime, 
133                           sampleValue newVal, 
134                           unsigned weight_) {
135     // why does this routine return a value (which is essentially useless)?
136
137     assert(firstSampleReceived);
138     assert(sampleTime > lastSampleEnd);
139
140     // used when it's a component of an aggregate.
141     lastSample += newVal;
142     lastSampleEnd = sampleTime;
143     weight = weight_;
144 }
145
146
147 struct sampleInterval aggregateSample::aggregateValues() {
148     struct sampleInterval ret;
149     timeStamp earlyestTime = HUGE_VAL;
150     ret.valid = false;
151
152     if (newParts.size()) {
153       // The new components do not need to have the same start time.
154       // We must wait until we have samples from all components, and then
155       // we need to find the first and second min start time for the new components
156       // and if first min == lastSampleEnd, we can aggregate from first to second.
157       // But we don't want to generate lots of very small samples in the case we have
158       // a large number of components, so we round the start times that are close
159       // enough to the min start time.
160
161       timeStamp newStart = HUGE_VAL;
162       timeStamp secondStart = HUGE_VAL;
163       for (unsigned u = 0; u < newParts.size(); u++) {
164         if ((!newParts[u]->firstValueReceived())) {
165           return ret;
166         }
167         if (newParts[u]->lastSampleStart < lastSampleEnd + 0.01) {
168           // round lastSampleStart to avoid generating very small aggregate
169           // samples. I'm using 0.01 as an arbitrary value. We should
170           // do some measurements to find a good value -- mjrg
171           newParts[u]->lastSampleStart = lastSampleEnd;
172         }
173         if (newParts[u]->lastSampleStart < newStart) {
174           newStart = newParts[u]->lastSampleStart;
175         }
176       }
177
178       assert (newStart >= lastSampleEnd);
179
180       if (parts.size() == 0)
181         lastSampleEnd = newStart;
182
183       if (newStart > lastSampleEnd) {
184         // new parts can't be aggregated yet
185         earlyestTime = newStart;
186       }
187       else { // newStart == lastSampleEnd
188         // find the new parts that are ready to be aggregated and move them to parts.
189         vector<sampleInfo *> temp;
190         vector<bool> rtemp;
191         for (unsigned u = 0; u < newParts.size(); u++) {
192           if (newParts[u]->lastSampleStart == newStart) {
193             parts += newParts[u];
194             removedParts += removedNewParts[u];
195           }
196           else {
197             if (newParts[u]->lastSampleStart < secondStart)
198               secondStart = newParts[u]->lastSampleStart;
199             temp += newParts[u];
200             rtemp += removedNewParts[u];
201           }
202         }
203         if (temp.size()) {
204           newParts = temp;
205           removedNewParts = rtemp;
206           earlyestTime = secondStart;
207         }
208         else {
209           newParts.resize(0);
210           removedNewParts.resize(0);
211         }
212       }
213     }
214
215     bool partsToRemove = false;
216
217     for (unsigned u = 0; u < parts.size(); u++) {
218       if (removedParts[u]) {
219         if (parts[u]->lastSampleEnd == parts[u]->lastSampleStart) {
220           partsToRemove = true;
221           continue;
222         }
223         if (parts[u]->lastSampleEnd < lastSampleEnd + 0.01) {
224            // round to avoid very small intervals;
225            parts[u]->lastSampleEnd = lastSampleEnd + 0.01;
226          }
227       }
228       if (parts[u]->lastSampleEnd < earlyestTime)
229         earlyestTime = parts[u]->lastSampleEnd;
230     }
231
232     if (partsToRemove) {
233       vector<sampleInfo *> temp;
234       vector<bool> rtemp;
235       for (unsigned u = 0; u < parts.size(); u++) {
236         if (!(removedParts[u] && parts[u]->lastSampleEnd == parts[u]->lastSampleStart)) {
237           temp += parts[u];
238           rtemp += removedParts[u];
239         }
240         else {
241           --(parts[u]->numAggregators);
242           if (parts[u]->numAggregators == 0) {
243             delete parts[u];
244           }
245         }
246       }
247       parts = temp;
248       removedParts = rtemp;
249       if (parts.size() == 0)
250         return ret;
251     }
252
253     sampleValue aggregateVal;
254     unsigned total_weight;
255
256     if (earlyestTime > lastSampleEnd + 0.001) {
257     // we can aggregate up to earlyest time.
258
259             aggregateVal = 0.0;
260             timeStamp fract;
261             timeStamp component;
262
263             int first = 1;
264             total_weight = 0;
265
266             for (unsigned u = 0; u < parts.size(); u++) {
267                 // assert(earlyestTime >= parts[u]->lastSampleStart);
268
269                 fract = (earlyestTime - lastSampleEnd)/
270                     (parts[u]->lastSampleEnd - parts[u]->lastSampleStart);
271                 component = (parts[u]->lastSample) * fract;
272
273                 assert(fract > 0.0);
274                 assert(fract <= 1.0);
275                 assert(component >= -0.01);
276
277                 parts[u]->lastSample -= component;
278
279                 // each list entry comes from a separate reporter
280                 switch (aggOp)
281                   {
282                   case aggSum:
283                     aggregateVal += component;
284                     break;
285                   case aggAvg:
286                     aggregateVal += parts[u]->weight*component;
287                     total_weight += parts[u]->weight;
288                     break;
289                   case aggMin:
290                     if (first) {
291                       aggregateVal = component;
292                       first = 0;
293                     } else if (component < aggregateVal)
294                       aggregateVal = component;
295                     break;
296                   case aggMax:
297                     if (component > aggregateVal)
298                       aggregateVal = component;
299                     break;
300                   }
301
302                 /* move forward our time of our earliest sample */
303                 parts[u]->lastSampleStart = earlyestTime;
304
305               }
306
307             if (aggOp == aggAvg)
308               aggregateVal /= total_weight;
309
310             ret.valid = true;
311             ret.start = lastSampleEnd;
312             ret.end = earlyestTime;
313             ret.value = aggregateVal;
314             assert(ret.value >= 0.0);
315
316             lastSampleStart = lastSampleEnd;
317             lastSampleEnd = earlyestTime;
318
319           }
320
321     return ret;
322 }