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