source: proiecte/swift/trunk/lib/hoard-371/src/hoardmanager.h @ 176

Last change on this file since 176 was 176, checked in by (none), 14 years ago
  • imported repo from "guagal"
File size: 10.3 KB
Line 
1// -*- C++ -*-
2
3/*
4
5  Heap Layers: An Extensible Memory Allocation Infrastructure
6 
7  Copyright (C) 2000-2007 by Emery Berger
8  http://www.cs.umass.edu/~emery
9  emery@cs.umass.edu
10 
11  This program is free software; you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation; either version 2 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
25*/
26
27#ifndef _HOARDMANAGER_H_
28#define _HOARDMANAGER_H_
29
30#include <stdlib.h>
31#include <new>
32
33// Hoard-specific Heap Layers
34#include "sassert.h"
35#include "statistics.h"
36#include "emptyclass.h"
37#include "array.h"
38#include "manageonesuperblock.h"
39
40
41// Generic Heap Layers
42#include "bins.h"
43#include "basehoardmanager.h"
44#include "emptyhoardmanager.h"
45#include "guard.h"
46#include "hldefines.h"
47
48using namespace HL;
49
50/**
51 *
52 * @class HoardManager
53 * @brief Manages superblocks by emptiness, returning them to the parent heap when empty enough.
54 * @author Emery Berger <http://www.cs.umass.edu/~emery>
55 *
56 **/
57
58namespace Hoard {
59
60template <class SourceHeap,
61          class ParentHeap,
62          class SuperblockType_,
63          int EmptinessClasses,
64          class LockType,
65          class thresholdFunctionClass,
66          class HeapType>
67class HoardManager : public BaseHoardManager<SuperblockType_>,
68                     public thresholdFunctionClass
69{
70public:
71
72  HoardManager (void)
73    : _magic (MAGIC_NUMBER)
74  {}
75
76  virtual ~HoardManager (void) {}
77
78  typedef SuperblockType_ SuperblockType;
79
80  /// This heap guarantees only double-word alignment.
81  enum { Alignment = sizeof(double) };
82
83
84  MALLOC_FUNCTION INLINE void * malloc (size_t sz)
85  {
86    Check<HoardManager, sanityCheck> check (this);
87    const int binIndex = binType::getSizeClass(sz);
88    size_t realSize = binType::getClassSize (binIndex);
89    assert (realSize >= sz);
90
91    // Iterate until we succeed in allocating memory.
92    void * ptr = getObject (binIndex, realSize);
93    if (ptr) {
94      return ptr;
95    } else {
96      return slowPathMalloc (realSize);
97    }
98  }
99
100
101  /// Put a superblock on this heap.
102  NO_INLINE void put (SuperblockType * s, size_t sz) {
103    HL::Guard<LockType> l (_theLock);
104
105    assert (s->getOwner() != this);
106    Check<HoardManager, sanityCheck> check (this);
107
108    const int binIndex = binType::getSizeClass(sz);
109
110    // Check to see whether this superblock puts us over.
111    Statistics& stats = _stats(binIndex);
112    int a = stats.getAllocated() + s->getTotalObjects();
113    int u = stats.getInUse() + (s->getTotalObjects() - s->getObjectsFree());
114
115    if (thresholdFunctionClass::function (u, a, sz)) {
116      // We've crossed the threshold function,
117      // so we move this superblock up to the parent.
118      _ph.put (reinterpret_cast<typename ParentHeap::SuperblockType *>(s), sz);
119    } else {
120      unlocked_put (s, sz);
121    }
122  }
123
124
125  /// Get an empty (or nearly-empty) superblock.
126  NO_INLINE SuperblockType * get (size_t sz, HeapType * dest) {
127    HL::Guard<LockType> l (_theLock);
128    Check<HoardManager, sanityCheck> check (this);
129    const int binIndex = binType::getSizeClass (sz);
130    SuperblockType * s = _otherBins(binIndex).get();
131    if (s) {
132      assert (s->isValidSuperblock());
133     
134      // Update the statistics, removing objects in use and allocated for s.
135      decStatsSuperblock (s, binIndex);
136      s->setOwner (dest);
137    }
138    // printf ("getting sb %x (size %d) on %x\n", (void *) s, sz, (void *) this);
139    return s;
140  }
141
142  /// Return one object to its superblock and update stats.
143  INLINE void free (void * ptr) {
144    Check<HoardManager, sanityCheck> check (this);
145
146    // Get the corresponding superblock.
147    SuperblockType * s = SuperHeap::getSuperblock (ptr);
148 
149    assert (s->getOwner() == this);
150
151    // Find out which bin it belongs to.
152    // Note that we assume that all pointers have been correctly
153    // normalized at this point.
154    assert (s->normalize (ptr) == ptr);
155
156    const size_t sz = s->getObjectSize ();
157    const int binIndex = binType::getSizeClass (sz);
158
159    // Free the object.
160    _otherBins(binIndex).free (ptr);
161
162
163    // Update statistics.
164    Statistics& stats = _stats(binIndex);
165    int u = stats.getInUse();
166    const int a = stats.getAllocated();
167    // FIX ME    assert (u > 0);
168    if (u > 0)
169      u--;
170    stats.setInUse (u);
171
172    // Free up a superblock if we've crossed the emptiness threshold.
173
174    if (thresholdFunctionClass::function (u, a, sz)) {
175
176      slowPathFree (binIndex, u, a);
177
178    }
179  }
180
181  INLINE void lock (void) {
182    _theLock.lock();
183  }
184
185  INLINE void unlock (void) {
186    _theLock.unlock();
187  }
188
189private:
190
191  typedef BaseHoardManager<SuperblockType_> SuperHeap;
192
193  enum { SuperblockSize = sizeof(SuperblockType_) };
194
195  /// Ensure that the superblock size is a power of two.
196  HL::sassert<((SuperblockSize & (SuperblockSize-1)) == 0)> verifyPowerOfTwo;
197
198  enum { MAGIC_NUMBER = 0xfeeddadd };
199
200  /// A magic number used for debugging.
201  const unsigned long _magic;
202
203  inline int isValid (void) const {
204    return (_magic == MAGIC_NUMBER);
205  }
206
207  sassert<sizeof(typename SuperblockType::Header) % sizeof(double) == 0>
208    verifyHeaderRightSize;
209
210
211  /// The type of the bin manager.
212  typedef HL::bins<typename SuperblockType::Header, SuperblockSize> binType;
213
214  /// How many bins do we need to maintain?
215  enum { NumBins = binType::NUM_BINS };
216
217  NO_INLINE void slowPathFree (int binIndex, int u, int a) {
218    // We've crossed the threshold.
219    // Remove a superblock and give it to the 'parent heap.'
220    Check<HoardManager, sanityCheck> check (this);
221   
222    //  printf ("HoardManager: this = %x, getting a superblock\n", this);
223   
224    SuperblockType * sb = _otherBins(binIndex).get ();
225   
226    // We should always get one.
227    assert (sb);
228    if (sb) {
229
230      const size_t sz = binType::getClassSize (binIndex);
231      Statistics& stats = _stats(binIndex);
232      int totalObjects = sb->getTotalObjects();
233      stats.setInUse (u - (totalObjects - sb->getObjectsFree()));
234      stats.setAllocated (a - totalObjects);
235
236      // Give it to the parent heap.
237      ///////// NOTE: We change the superblock type here!
238      ///////// THIS HAD BETTER BE SAFE!
239      _ph.put (reinterpret_cast<typename ParentHeap::SuperblockType *>(sb), sz);
240      assert (sb->isValidSuperblock());
241
242    }
243  }
244
245
246  NO_INLINE void unlocked_put (SuperblockType * s, size_t sz) {
247    if (!s || !s->isValidSuperblock()) {
248      return;
249    }
250
251    Check<HoardManager, sanityCheck> check (this);
252
253    const int binIndex = binType::getSizeClass(sz);
254
255    // Now put it on this heap.
256    s->setOwner (reinterpret_cast<HeapType *>(this));
257    _otherBins(binIndex).put (s);
258
259    // Update the heap statistics with the allocated and in use stats
260    // for the superblock.
261
262    addStatsSuperblock (s, binIndex);
263    assert (s->isValidSuperblock());
264
265  }
266
267  void addStatsSuperblock (SuperblockType * s, int binIndex) {
268    Statistics& stats = _stats(binIndex);
269   
270    int a = stats.getAllocated();
271    int u = stats.getInUse();
272    int totalObjects = s->getTotalObjects();
273    stats.setInUse (u + (totalObjects - s->getObjectsFree()));
274    stats.setAllocated (a + totalObjects);
275  }
276
277
278  void decStatsSuperblock (SuperblockType * s, int binIndex) {
279    Statistics& stats = _stats(binIndex);
280   
281    int a = stats.getAllocated();
282    int u = stats.getInUse();
283    int totalObjects = s->getTotalObjects();
284    stats.setInUse (u - (totalObjects - s->getObjectsFree()));
285    stats.setAllocated (a - totalObjects);
286  }
287
288  MALLOC_FUNCTION NO_INLINE void * slowPathMalloc (size_t sz) {
289    const int binIndex = binType::getSizeClass (sz);
290    size_t realSize = binType::getClassSize (binIndex);
291    assert (realSize >= sz);
292    for (;;) {
293      Check<HoardManager, sanityCheck> check (this);
294      void * ptr = getObject (binIndex, realSize);
295      if (ptr) {
296        return ptr;
297      } else {
298        Check<HoardManager, sanityCheck> check (this);
299        // Return null if we can't allocate another superblock.
300        if (!getAnotherSuperblock (realSize)) {
301          //      fprintf (stderr, "HoardManager::malloc - no memory.\n");
302          return 0;
303        }
304      }
305    }
306  }
307
308  /// Get one object of a particular size.
309  MALLOC_FUNCTION INLINE void * getObject (int binIndex, size_t sz) {
310    Check<HoardManager, sanityCheck> check (this);
311    void * ptr = _otherBins(binIndex).malloc (sz);
312    if (ptr) {
313      // We got one. Update stats.
314      int u = _stats(binIndex).getInUse();
315      _stats(binIndex).setInUse (u+1);
316    }
317    return ptr;
318  }
319
320  friend class sanityCheck;
321
322  class sanityCheck {
323  public:
324    inline static void precondition (HoardManager * h) {
325      checkInvariant(h);
326    }
327    inline static void postcondition (HoardManager * h) {
328      checkInvariant(h);
329    }
330  private:
331    inline static void checkInvariant (HoardManager * h) {
332      assert (h->isValid());
333    }
334  };
335
336public:
337
338  NO_INLINE void * getAnotherSuperblock (size_t sz) {
339
340    // NB: This function should be on the slow path.
341
342    SuperblockType * sb = NULL;
343
344    // Try the parent heap.
345    // NOTE: We change the superblock type here!
346    sb = reinterpret_cast<SuperblockType *>(_ph.get (sz, reinterpret_cast<ParentHeap *>(this)));
347
348    if (sb) {
349      if (!sb->isValidSuperblock()) {
350        // As above - drop any invalid superblocks.
351        sb = NULL;
352      }
353
354    } else {
355      // Nothing - get memory from the source.
356      void * ptr = _sourceHeap.malloc (SuperblockSize);
357      if (!ptr) {
358        return 0;
359      }
360      sb = new (ptr) SuperblockType (sz);
361    }
362
363    // Put the superblock into its appropriate bin.
364    if (sb) {
365      unlocked_put (sb, sz);
366    }
367    return sb;
368  }
369
370private:
371
372  LockType _theLock;
373
374  /// Usage statistics for each bin.
375  Array<NumBins, Statistics> _stats;
376
377  typedef SuperblockType * SuperblockTypePointer;
378
379  typedef EmptyClass<SuperblockType, EmptinessClasses> OrganizedByEmptiness;
380
381  typedef ManageOneSuperblock<OrganizedByEmptiness> BinManager;
382
383  /// Bins that hold superblocks for each size class.
384  Array<NumBins, BinManager> _otherBins;
385
386  /// The parent heap.
387  ParentHeap _ph;
388
389  /// Where memory comes from.
390  SourceHeap _sourceHeap;
391
392};
393
394}
395
396#endif
Note: See TracBrowser for help on using the repository browser.