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