Moved int64iostream files from common to pdutil subdirectory.
[dyninst.git] / paradynd / src / fastInferiorHeapHKs.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 // $Id: fastInferiorHeapHKs.C,v 1.16 2000/07/28 18:29:08 pcroth Exp $
43 // contains housekeeping (HK) classes used as the first template input tpe
44 // to fastInferiorHeap (see fastInferiorHeap.h and .C)
45
46 #include "dyninstAPI/src/process.h"
47 #include "dyninstAPI/src/pdThread.h"
48 #include "metric.h"
49 #include "fastInferiorHeapHKs.h"
50
51 #if defined(i386_unknown_nt4_0)
52 #  include "pdutil/h/int64iostream.h"
53 #endif // defined(i386_unknown_nt4_0)
54
55
56 // Define some static member vrbles:
57 // In theory, these values are platform-dependent; for now, they're always
58 // one million since the timer "getTime" routines in rtinst always return usecs.
59 // But that will surely change one day...e.g. some platforms might start returning
60 // cycles.
61 unsigned wallTimerHK::normalize = 1000000;
62 unsigned processTimerHK::normalize = 1000000;
63
64 genericHK &genericHK::operator=(const genericHK &src) {
65    if (&src == this)
66       return *this; // the usual check for x=x
67
68    mi            = src.mi;
69    trampsUsingMe = src.trampsUsingMe;
70
71    return *this;
72 }
73
74 void genericHK::makePendingFree(const vector<Address> &iTrampsUsing) {
75    // now we initialize trampsUsingMe.  iTrampsUsing provides us with the starting
76    // addr of each such tramp, but we need to look at the old-style inferiorHeap
77    // (process.C) to find the tramp length and hence its endAddr.  Yuck.
78
79 //   cout << "welcome to genericHK::makePendingFree" << endl;
80
81    trampsUsingMe.resize(iTrampsUsing.size());
82       // we may shrink it later if some entries are shown to be unneeded
83
84    unsigned actualNumTramps=0;
85
86    for (unsigned lcv=0; lcv < iTrampsUsing.size(); lcv++) {
87       assert(mi);
88
89       const class process &inferiorProc = *(mi->proc());
90          // don't ask why 'class' is needed here because I don't know myself.
91
92       const dictionary_hash<Address, heapItem*> &heapActivePart =
93         inferiorProc.heap.heapActive;
94
95       const Address trampBaseAddr = iTrampsUsing[lcv];
96       heapItem *trampHeapItem;
97       // fills in "trampHeapItem" if found:
98       if (!heapActivePart.find(trampBaseAddr, trampHeapItem)) {
99          // hmmm...the trampoline was deleted, so I guess we don't need to check it
100          //        in the future.
101          continue; // next trampoline check
102       }
103
104       trampRange tempTrampRange;
105       tempTrampRange.startAddr = trampBaseAddr;
106       tempTrampRange.endAddr = trampBaseAddr + trampHeapItem->length - 1;
107
108       trampsUsingMe[actualNumTramps++] = tempTrampRange;
109    }
110
111    trampsUsingMe.resize(actualNumTramps);
112 }
113
114 bool genericHK::tryGarbageCollect(const vector<Address> &PCs) {
115    // returns true iff GC succeeded.
116    // We may of course assume that this routine is only called if the
117    // item in question is in pending-free state.
118    // Similar to isFreeOK of process.C...
119    // PCs is a list of PC-register values representing a stack trace in the inferior
120    // process.  It's OK to garbage collect (and we turn true) if none of the PCs
121    // in the stack trace fall within any of the trampolines who are using us.
122
123    for (unsigned pointlcv=0; pointlcv < trampsUsingMe.size(); pointlcv++) {
124       const trampRange &theTrampRange = trampsUsingMe[pointlcv];
125
126       // If any of the PCs of the stack trace are within theTrampRange, then it's unsafe
127       // to delete us.
128
129       for (unsigned stacklcv=0; stacklcv < PCs.size(); stacklcv++) {
130          const Address stackPC = PCs[stacklcv];
131
132          // If this PC falls within the range of the trampoline we're currently
133          // looking at, then it's unsafe to delete it.
134          if (stackPC >= theTrampRange.startAddr &&
135              stackPC <= theTrampRange.endAddr)
136             return false; // sorry, can't delete
137       }
138    }
139
140    // GC has succeeded!  Do some cleanup and return true:
141    trampsUsingMe.resize(0); // we won't be needing this anymore
142    return true;
143 }
144
145 /* ************************************************************************** */
146
147 intCounterHK &intCounterHK::operator=(const intCounterHK &src) {
148    if (&src == this)
149       return *this; // the usual check for x=x
150
151    lowLevelId = src.lowLevelId;
152    genericHK::operator=(src);
153
154    return *this;
155 }
156
157 bool intCounterHK::perform(const intCounter &dataValue, process *inferiorProc) {
158    // returns true iff the process succeeded; i.e., if we were able to grab a
159    // consistent value for the intCounter and process without any waiting.  Otherwise,
160    // we return false and don't process and don't wait.
161
162    const int val        = dataValue.value;
163       // that was the sampling.  Currently, we don't check to make sure that we
164       // sampled a consistent value, since we assume that writes to integers
165       // are never partial.  Once we extent intCounters to, say, 64 bits, we'll
166       // need to be more careful and use a scheme similar to that used by the
167       // process and wall timers...
168
169    // To avoid race condition, don't use 'dataValue' after this point!
170
171 //#ifdef SHM_SAMPLING_DEBUG
172    const unsigned id    = dataValue.id.id;
173       // okay to read dataValue.id since there's no race condition with it.
174    assert(id == this->lowLevelId); // verify our new code is working right
175       // eventually, id field can be removed from dataValue, saving space
176
177    extern dictionary_hash<unsigned, metricDefinitionNode*> midToMiMap;
178    metricDefinitionNode *theMi;
179    if (!midToMiMap.find(id, theMi)) { // fills in "theMi" if found
180       // sample not for valid metric instance; no big deal; just drop sample.
181       // (But perhaps in the new scheme this can be made an assert failure?)
182       cerr << "intCounter sample not for valid metric instance, so dropping" << endl;
183       return true; // is this right?
184    }
185    assert(theMi == this->mi); // verify our new code is working right
186       // eventually, id field can be removed from inferior heap; we'll
187       // just use this->mi.
188
189    // note: we do _not_ assert that id==mi->getMId(), since mi->getMId() returns
190    // an entirely different identifier that has no relation to our 'id'
191 //#endif
192
193    assert(mi);
194    assert(mi->proc() == inferiorProc);
195
196    mi->updateValue(getCurrWallTime(), val);
197       // the integer version of updateValue() (no int-->float conversion -- good)
198
199    return true;
200 }
201
202 /* ************************************************************************** */
203
204 wallTimerHK &wallTimerHK::operator=(const wallTimerHK &src) {
205    if (&src == this)
206       return *this; // the usual check for x=x
207
208    lowLevelId        = src.lowLevelId;
209    lastTimeValueUsed = src.lastTimeValueUsed;
210
211    genericHK::operator=(src);
212
213    return *this;
214 }
215
216 static time64 calcTimeValueToUse(int count, time64 start,
217                                              time64 total,
218                                              time64 currentTime) {
219    if (count == 0)
220       // inactive timer; the easy case; just report total.
221       return total;
222
223    if (count < 0)
224       // ??? a strange case, shouldn't happen.  If this occurs, it means
225       // that an imbalance has occurred w.r.t. startTimer/stopTimer, and
226       // that we don't really know if the timer is active or not.
227       return total;
228
229    // Okay, now for the active timer case.  Report the total plus (now - start).
230    // A wrinkle: for some reason, we occasionally see currentTime < start, which
231    // should never happen.  In that case, we'll just report total  (why is it
232    // happening?)
233    if (currentTime < start)
234       return total;
235    else 
236       return total + (currentTime - start);
237 }
238
239 bool wallTimerHK::perform(const tTimer &theTimer, process *) {
240    // returns true iff the process succeeded; i.e., if we were able to read
241    // a consistent value of the tTimer, and process it.  Otherwise, returns false,
242    // doesn't process and doesn't wait.
243
244    // We sample like this:
245    // read protector2, read values, read protector1.  If protector values are equal,
246    // then process using a copy of the read values.  Otherwise, return false.
247    // This algorithm is from [Lamport 77], and allows concurrent reading and writing.
248    // If someday there becomes multiple writers, then we'll have to make changes...
249
250    // We used to take in a wall time to use as the time-of-sample.  But we've found
251    // that the wall time (when used as fudge factor when sampling an active process
252    // timer) must be taken at the same time the sample is taken to avoid incorrectly
253    // scaled fudge factors, leading to jagged spikes in the histogram (i.e.
254    // incorrect samples).  This is too bad; it would be nice to read the wall time
255    // just once per paradynd sample, instead of once per timer per paradynd sample.
256
257    volatile const int prot2 = theTimer.protector2;
258
259    // Do these 4 need to be volatile as well to ensure that they're read
260    // between the reading of protector2 and protector1?  Probably not, since those
261    // two are volatile; but let's keep an eye on the generated assembly code...
262    const time64 start = theTimer.start;
263    const time64 total = theTimer.total;
264    const int    count = theTimer.counter;
265    const time64 currWallTime = getCurrWallTime();
266
267    volatile const int prot1 = theTimer.protector1;
268
269    if (prot1 != prot2)
270       // We read a (possibly) inconsistent value for the timer, so we reject it.
271       return false;
272
273    /* don't use 'theTimer' after this point! (avoid race condition).  To ensure
274       this, we call calcTimeValueToUse(), which doesn't use 'theTimer' */
275    time64 timeValueToUse = calcTimeValueToUse(count, start,
276                                               total, currWallTime);
277
278    // Check for rollback; update lastTimeValueUsed (the two go hand in hand)
279    if (timeValueToUse < lastTimeValueUsed) {
280       // Timer rollback!  An assert failure.
281       const char bell = 07;
282       cerr << "wallTimerHK::perform(): wall timer rollback ("
283           << timeValueToUse << "," << lastTimeValueUsed << ")"
284           << bell << endl;
285       cerr << "timer was " << (count > 0 ? "active" : "inactive") << endl;
286
287       assert(false);
288    }
289    else
290       lastTimeValueUsed = timeValueToUse;
291
292 #ifdef SHM_SAMPLING_DEBUG
293    // It's okay to use theTimer.id because it's not susceptible to race conditions
294    const unsigned id    = theTimer.id.id;
295    assert(id == this->lowLevelId); // verify our new code is working right
296
297    extern dictionary_hash<unsigned, metricDefinitionNode*> midToMiMap;
298    metricDefinitionNode *theMi;
299    if (!midToMiMap.find(id, theMi)) { // fills in "theMi" if found
300       // sample not for valid metric instance; no big deal; just drop sample.
301       cout << "NOTE: dropping sample unknown wallTimer id " << id << endl;
302       return true; // is this right?
303    }
304    assert(theMi == this->mi); // verify our new code is working right
305
306    // note: we do _not_ assert that id==mi->getMId(), since mi->getMId() returns
307    // an entirely different identifier that has no relation to our 'id'
308 #endif
309
310    const double valueToReport = (double)timeValueToUse / normalize;
311    
312    mi->updateValue(currWallTime, (float)valueToReport);
313
314    return true;
315 }
316
317 /* ************************************************************************** */
318
319 processTimerHK &processTimerHK::operator=(const processTimerHK &src) {
320    if (&src == this)
321       return *this; // the usual check for x=x
322
323    lowLevelId        = src.lowLevelId;
324    lastTimeValueUsed = src.lastTimeValueUsed;
325
326 #if defined(MT_THREAD)
327    vTimer = NULL ;
328 #endif
329    genericHK::operator=(src);
330
331    return *this;
332 }
333
334 bool processTimerHK::perform(const tTimer &theTimer, process *inferiorProc) {
335    // returns true iff the process succeeded; i.e., if we were able to grab the
336    // mutex for this tTimer and process without any waiting.  Otherwise,
337    // we return false and don't process and don't wait.
338
339    // Timer sampling is trickier than counter sampling.  There are more
340    // race conditions and other factors to carefully consider.
341
342    // see the corresponding wall-timer routine for comments on how we guarantee
343    // a consistent read value...
344
345    // We used to take in a wall time to use as the time-of-sample, and a process
346    // time to use as the current-process-time for use in fudge factor when sampling
347    // an active process timer.  But we've found that both values must be taken at
348    // the same time the sample is taken to avoid incorrect values, leading to
349    // jagged spikes in the histogram (i.e. incorrect samples).  This is too bad; it
350    // would be nice to read these times just once per paradynd sample, instead of
351    // once per timer per paradynd sample.
352
353    volatile const int protector2 = theTimer.protector2;
354
355    // Do the following vrbles need to be volatile to ensure that they're read
356    // between the reading of protector2 and protector1?  Probably not, but
357    // we should keep an eye on the generated assembly to be sure...
358
359    // We always need to use the first 2 vrbles:
360    const int    count = theTimer.counter;
361    const time64 total = theTimer.total;
362    const time64 start = (count > 0) ? theTimer.start : 0; // not needed if count==0
363
364 #if defined(MT_THREAD)
365    const tTimer* vt   = (tTimer*) theTimer.vtimer ;
366    unsigned long long inferiorCPUtime ;
367    if (vt == (tTimer*) -1) {
368      inferiorCPUtime = (count>0)?inferiorProc->getInferiorProcessCPUtime():0;
369    } else {
370      if (vt) {
371        RTINSTsharedData *RTsharedDataInParadynd 
372            =((RTINSTsharedData*) inferiorProc->getRTsharedDataInParadyndSpace()) ; 
373        RTINSTsharedData *RTsharedDataInApplic 
374            =((RTINSTsharedData*) inferiorProc->getRTsharedDataInApplicSpace()) ; 
375        vTimer = RTsharedDataInParadynd->virtualTimers + 
376            (int)(vt- RTsharedDataInApplic->virtualTimers);
377      }
378      bool success = true ; // count <=0 should return true
379      inferiorCPUtime =(count>0)?pdThread::getInferiorVtime(vTimer,inferiorProc, success):0 ; 
380      if (!success)
381        return false ;
382    }
383 #else   
384    const time64 inferiorCPUtime
385      = (count>0)?inferiorProc->getInferiorProcessCPUtime(/*theTimer.lwp_id*/):0;
386 #endif 
387
388    // This protector read and comparison must happen *after* we obtain the inferior
389    // CPU time or thread virtual time, or we have a race condition resulting in lots
390    // of annoying timer rollback warnings.  In the long run, our data is still 
391    // correct, but individual samples will be bad.
392    volatile const int protector1 = theTimer.protector1;
393    if (protector1 != protector2)
394       return false;
395
396    // Also cheating; see below.
397    // the fudge factor is needed only if count > 0.
398    const time64 theWallTime = getCurrWallTime();
399    // This is cheating a little; officially, this call should be inside
400    // of the two protector vrbles.  But, it was taking too long...
401
402
403    /* don't use 'theTimer' after this point! (avoid race condition).  To ensure
404       this, we call calcTimeValueToUse() without passing 'theTimer' */
405    time64 timeValueToUse = calcTimeValueToUse(count, start,
406                                               total, inferiorCPUtime);
407    // Check for rollback; update lastTimeValueUsed (the two go hand in hand)
408    // cerr <<"lastTimeValueUsed="<< lastTimeValueUsed << endl ;
409    if (timeValueToUse < lastTimeValueUsed) {
410 #if  !defined(MT_THREAD)
411    // Timer could roll back in the case that the per-thread
412    // virtual timer is reused by another thread, to avoid this to happen, we should
413    // reuse them with a least recently used strategy.
414    // See DYNINST_hash_delete in RTinst.c
415       const char bell = ' '; //07;
416       cerr << "processTimerHK::perform(): process timer rollback (" 
417            << timeValueToUse << "," << lastTimeValueUsed << ")" 
418            << bell << endl;
419       cerr << "timer was " << (count > 0 ? "active" : "inactive") 
420            << ", id=" << theTimer.id.id 
421            << ", start=" << start
422            << ", total=" << total
423            << ", inferiorCPUtime=" << inferiorCPUtime
424            << endl;
425
426 #endif
427       timeValueToUse = lastTimeValueUsed;
428
429 //      assert(false);
430    }
431    else
432       lastTimeValueUsed = timeValueToUse;
433
434 //#ifdef SHM_SAMPLING_DEBUG
435    const unsigned id    = theTimer.id.id;
436
437    assert(id == this->lowLevelId); // verify our new code is working right
438
439    extern dictionary_hash<unsigned, metricDefinitionNode*> midToMiMap;
440    metricDefinitionNode *theMi;
441    if (!midToMiMap.find(id, theMi)) { // fills in "theMi" if found
442       // sample not for valid metric instance; no big deal; just drop sample.
443       cerr << "procTimer id " << id 
444            << " not found in midToMiMap so dropping sample of val " 
445            << (double)timeValueToUse / normalize << " for mi " 
446            << (void*)mi << " proc pid " << inferiorProc->getPid() << endl;
447       assert(0);
448       return true; // is this right?
449    }
450    assert(theMi == this->mi); // verify our new code is working right
451
452    // note: we do _not_ assert that id==mi->getMId(), since mi->getMId() returns
453    // an entirely different identifier that has no relation to our 'id'
454 //#endif
455
456    const double valueToReport = (double)timeValueToUse / normalize;
457
458    mi->updateValue(theWallTime, (float)valueToReport);
459
460    return true;
461 }