gwnavruntime/kernel/SF_MemoryHeap.h Source File

SF_MemoryHeap.h
Go to the documentation of this file.
1 /*
2 * Copyright 2016 Autodesk, Inc. All rights reserved.
3 * Use of this software is subject to the terms of the Autodesk license agreement and any attachments or Appendices thereto provided at the time of installation or download,
4 * or which otherwise accompanies this software in either electronic or hard copy form, or which is signed by you and accepted by Autodesk.
5 */
6 
7 /**************************************************************************
8 
9 PublicHeader: Kernel
10 Filename : KY_MemoryHeap.h
11 Content : Public memory heap class declaration.
12 Created : October 1, 2008
13 Authors : Michael Antonov, Maxim Shemanarev
14 
15 **************************************************************************/
16 
17 #ifndef INC_KY_Kernel_MemoryHeap_H
18 #define INC_KY_Kernel_MemoryHeap_H
19 
25 
26 namespace Kaim {
27 
28 // *** Heap-Specific Statistics identifiers
29 //------------------------------------------------------------------------
30 enum StatHeap
31 {
32  // StatHeap_Summary is a root stat group for all of heap-custom statistics returned by StatHeap.
33  StatHeap_Summary = StatHeap_Start,
34  StatHeap_TotalFootprint, // Total memory allocated for heap and children.
35  StatHeap_LocalFootprint, // Total memory allocated for heap.
36  StatHeap_ChildFootprint, // Total footprint of all child heaps.
37  StatHeap_ChildHeaps, // The number of child heaps.
38  StatHeap_LocalUsedSpace, // Used memory within footprint.
39  StatHeap_SysDirectSpace, // Memory allocated directly from SysAlloc.
40  StatHeap_Bookkeeping, // Amount of memory used for heap bookkeeping.
41  StatHeap_DebugInfo, // Amount of memory used for heap debug information.
42  StatHeap_Segments, // Number of allocated segments.
43  StatHeap_Granularity, // Specified heap granularity.
44  StatHeap_DynamicGranularity, // Current dynamic granularity.
45  StatHeap_Reserve // Heap reserve.
46  // 3 slots left. Check/modify StatGroup in "Stat.h" for more.
47 };
48 
49 namespace HeapMH { class RootMH; }
50 namespace Heap { class MemVisitor; class SegVisitor; }
51 
52 // ***** MemoryHeap
53 //------------------------------------------------------------------------
54 //
55 // Memory heap from which allocations take place. This interface supports
56 // creation of child heaps for dedicated purposes, such that when child
57 // heaps are released all of their memory is released as well. The benefit
58 // of child heaps is that they grab memory in large chunks of Granularity
59 // from the root, such that all of heap-local allocations take place in
60 // those chunks. This strategy reduces overall fragmentation, since once
61 // child heap is released it will make all of its large chunks available
62 // for reuse.
63 //
64 // The child memory heap use in Scaleform relies on ability to determine
65 // target heap based on the address within allocation in it, done by
66 // AllocAutoHeap function. This function takes an address that must be
67 // within some other allocation of the desired heap and allocated new memory
68 // within the same heap as that allocation. Note that the passed address
69 // does NOT have to point to the head of previous allocation, it can also
70 // be in the middle of it. This functionality allows convenient initialization
71 // of aggregate structures and arrays located within other objects, their
72 // allocations will automatically take place within the same heap as the
73 // containing object.
74 //
75 // Internally, heaps rely on SysAlloc interface for allocating large blocks
76 // of system memory; this interface is specified in Kaim::System constructor.
77 // Developers can subsitute Scaleform allocator by re-implementing that interface.
78 
79 // *** Predeclarations
80 //------------------------------------------------------------------------
81 
82 class MemoryHeap : public ListNode<MemoryHeap>
83 {
84  friend class MemoryHeapMH;
85 public:
86  enum HeapFlags
87  {
88  Heap_ThreadUnsafe = 0x0001,
89 
90  // Significantly speeds up small allocations, up to 8*MinAlign,
91  // but may result in higher memory overhead. The smallest heap
92  // size will typically increase by about 8*PageSize. For the
93  // PageSize=4K it's 32K. If there are thousands of small
94  // allocations existing simultaneously, the extra memory
95  // overhead is low.
96  Heap_FastTinyBlocks = 0x0002,
97 
98  // Fixed Granularity means that memory segments will have as small
99  // size as possible. It slightly reduces the total footprint and
100  // eases returning memory to the system, but may slow down the
101  // allocations. It also makes the heap less realloc-friendly.
102  Heap_FixedGranularity = 0x0004,
103 
104  // This flag is set if this is the root (global) memory heap.
105  Heap_Root = 0x0008,
106 
107  // Set if this heap keeps debug data in an alternative heap.
108  // If not, then this heap does not track debug information.
109  Heap_NoDebugInfo = 0x0010,
110 
111  // This flag can be set by the user for debug tool allocations, such as the
112  // player HUD. Scaleform tools can choose to omit these heaps from information
113  // reporting or report them separately. This flag is for user information only,
114  // it has no effect on heap implementation.
115  Heap_UserDebug = 0x1000
116  };
117 
118  enum RootHeapParameters
119  {
120  RootHeap_MinAlign = 16,
121  RootHeap_Granularity = 16*1024,
122  RootHeap_Reserve = 16*1024,
123  RootHeap_Threshold = 256*1024,
124  RootHeap_Limit = 0
125  };
126 
127  struct HeapDesc
128  {
129  // Capability flags such as thread safety, debug support, etc.
130  unsigned Flags;
131 
132  // Minimum alignment that will be enforced for all allocations from heap.
133  UPInt MinAlign;
134 
135  // Granularity represents the smallest block size that the heap
136  // will request from the "root" heap memory system, which ultimately
137  // routes to SysAlloc. In other words, this is the size multiple by
138  // which the heap will grow. For example, with the default value of 16K,
139  // the first allocation of 10 bytes on the heap will allocate a 16K block;
140  // from that point on all of the further heap allocations will be serviced from
141  // that block until it is exhausted. Once exhausted, an additional block of
142  // granularity will be allocated. If all of the allocation within a block
143  // are free, it will similarly be returned to root heap manager for reuse
144  // in other heaps or return to SysAlloc.
145  UPInt Granularity;
146 
147  // Smallest maintained reserve, or pre-allocated reserve. Data within
148  // the reserve will not be given back to parent heap or system until
149  // the heap is released. Must be multiple of Granularity.
150  UPInt Reserve;
151 
152  // If the allocation size exceeds this threshold the allocation
153  // is being redirected directly to SysAlloc.
154  UPInt Threshold;
155 
156  // If not 0, specifies the limit on the amount of memory used by heap.
157  // Any attempt to allocate more will fail returning null. Must be
158  // multiple of Granularity.
159  UPInt Limit;
160 
161  // An arbitrary integer to associate the heap with some additional
162  // information. In particular, the Id is associated with the color to
163  // be displayed in the memory monitor. If the Id is 0 there is no
164  // associations, but the heap will be displayed anyway. The only
165  // difference is persistence. Heaps with IDs will have guaranteed
166  // persistent colors to be easily distinguishable from other ones.
167  UPInt HeapId;
168 
169  // Memory arena used for this heap. The arena must be created, see
170  // MemoryHeap::CreateArena. Arena 0 is reserved for the use by default.
171  UPInt Arena;
172 
173  HeapDesc(unsigned flags = 0,
174  UPInt minAlign = 16,
175  UPInt granularity = 8*1024,
176  UPInt reserve = 8*1024,
177  UPInt threshold=~UPInt(0),
178  UPInt limit = 0,
179  UPInt heapId = 0,
180  UPInt arena = 0)
181  : Flags(flags), MinAlign(minAlign),
182  Granularity(granularity), Reserve(reserve),
183  Threshold(threshold), Limit(limit),
184  HeapId(heapId), Arena(arena)
185  { }
186 
187  void Clear()
188  {
189  Flags = 0;
190  Granularity = 0;
191  MinAlign = 16;
192  Reserve = 0;
193  Threshold = ~UPInt(0);
194  Limit = 0;
195  HeapId = 0;
196  Arena = 0;
197  }
198  };
199 
200  // Root heap descriptor. This class exists for the sole purpose of using
201  // its default constructor for initializing a root heap object, as root default
202  // arguments are different from those of child heaps.
203  struct RootHeapDesc : public HeapDesc
204  {
205  RootHeapDesc()
206  : HeapDesc(0, RootHeap_MinAlign,
207  RootHeap_Granularity, RootHeap_Reserve,
208  RootHeap_Threshold, RootHeap_Limit, HeapId_Global)
209  { }
210  };
211 
212  //--------------------------------------------------------------------
213  struct HeapInfo
214  {
215  HeapDesc Desc;
216 
217  // Parent heap, if this describes a nested heap. Null for root heap.
218  MemoryHeap* pParent;
219 
220  // Heap name. Can be in UTF-8.
221  char* pName;
222  };
223 
224  //--------------------------------------------------------------------
225  struct HeapVisitor
226  {
227  virtual ~HeapVisitor() { }
228 
229  // Called for each child heap within parent; the child heap is
230  // guaranteed to stay alive during the call as long as parent is alive too.
231  // Implementation of Visit is not allowed to allocate memory
232  // from childHeap due to a risk of deadlock (it can allocate from
233  // parent or other heaps).
234  virtual void Visit(MemoryHeap* parentHeap, MemoryHeap *childHeap) = 0;
235  };
236 
237  //--------------------------------------------------------------------
238  struct LimitHandler
239  {
240  virtual ~LimitHandler() {}
241  // The handler that is called when the limit is reached. The handler
242  // can try to free memory of at least "overLimit" size in summary
243  // (release cached elements, invoke GC, etc).
244  // If freeing is not possible or there's not enough size of elements
245  // being released the function can increase the heap limit
246  // (MemoryHeap::SetLimit). In both cases it should return true.
247  // If neither is possible the function returns false and then the
248  // allocation call fails (returns 0).
249  virtual bool OnExceedLimit(MemoryHeap* heap, UPInt overLimit) = 0;
250 
251  // The function is called when the segment is freeing. It allows the
252  // application algorithm to decrease the limit when necessary.
253  virtual void OnFreeSegment(MemoryHeap* heap, UPInt freeingSize) = 0;
254  };
255 
256  //--------------------------------------------------------------------
257  struct HeapTracer
258  {
259  virtual ~HeapTracer() {}
260  virtual void OnCreateHeap(const MemoryHeap* heap) = 0;
261  virtual void OnDestroyHeap(const MemoryHeap* heap) = 0;
262  virtual void OnAlloc(const MemoryHeap* heap, UPInt size, UPInt align, unsigned sid, const void* ptr) = 0;
263  virtual void OnRealloc(const MemoryHeap* heap, const void* oldPtr, UPInt newSize, const void* newPtr) = 0;
264  virtual void OnFree(const MemoryHeap* heap, const void* ptr) = 0;
265  };
266 
267  //--------------------------------------------------------------------
268  struct RootStats
269  {
270  UPInt SysMemFootprint;
271  UPInt SysMemUsedSpace;
272  UPInt PageMapFootprint;
273  UPInt PageMapUsedSpace;
274  UPInt BookkeepingFootprint;
275  UPInt BookkeepingUsedSpace;
276  UPInt DebugInfoFootprint;
277  UPInt DebugInfoUsedSpace;
278  UPInt UserDebugFootprint;
279  UPInt UserDebugUsedSpace;
280  };
281 
282 protected:
283  MemoryHeap(); // Explicit creation and destruction is prohibited
284  virtual ~MemoryHeap() {}
285 
286 public:
287 
288  // *** Initial bootstrapping and final clean-up class factory functions
289  //
290  //--------------------------------------------------------------------
291  static void InitMH(SysAlloc* sysAllocMH);
292  static void CleanUpMH();
293 
294  // Creates the root heap. The function can be called only once.
295  // The second call will return 0. Call ReleaseRootHeap before creating another root heap.
296  static MemoryHeap* CreateRootHeapMH();
297  static MemoryHeap* CreateRootHeapMH(const HeapDesc& desc);
298 
299  // Releases root heap and/or de-initializes it; intended to be the opposite
300  // of the heap-specific CreateRootHeap() static function. ReleaseRootHeap is
301  // called during System::Destroy before the global heap is reset.
302  // Its implementation may or may not include ref-counting semantics.
303  static void ReleaseRootHeapMH();
304 
305 
306  // *** Operations with memory arenas
307  //
308  //--------------------------------------------------------------------
309  virtual void DestroyArena(UPInt arena) = 0;
310  virtual bool ArenaIsEmpty(UPInt arena) = 0;
311 
312  // *** Initialization
313  //
314  // Creates a nested child heap; The heap should be destroyed
315  // by calling release. If child heap creation failed due to
316  // out-of-memory condition, returns 0. If child heap creation
317  // is not supported a pointer to the same parent heap will be returned.
318  //--------------------------------------------------------------------
319  virtual MemoryHeap* CreateHeap(const char* name,
320  const HeapDesc& desc) = 0;
321 
322  MemoryHeap* CreateHeap(const char* name,
323  unsigned flags = 0,
324  UPInt minAlign = 16,
325  UPInt granularity = 16*1024,
326  UPInt reserve = 16*1024,
327  UPInt threshold=~UPInt(0),
328  UPInt limit = 0,
329  UPInt heapId = 0,
330  UPInt arena = 0)
331  {
332  HeapDesc desc(flags, minAlign, granularity, reserve, threshold, limit, heapId, arena);
333  return CreateHeap(name, desc);
334  }
335 
336  // *** Service functions
337  //--------------------------------------------------------------------
338 
339  // Fills in heap descriptor with information.
340  void GetHeapInfo(HeapInfo* infoPtr) const;
341 
342  const char* GetName() const { return Info.pName; }
343  UPInt GetId() const { return Info.Desc.HeapId;}
344  MemoryHeap* GetParentHeap() const { return Info.pParent; }
345  unsigned GetFlags() const { return Info.Desc.Flags; }
346  UPInt GetGranularity()const { return Info.Desc.Granularity; }
347 
348  virtual void SetLimitHandler(LimitHandler* handler) = 0;
349  virtual void SetLimit(UPInt newLimit) = 0;
350  UPInt GetLimit() const { return Info.Desc.Limit; }
351 
352  // Determines if the heap is thread safe or not. One benefit of thread safe heap
353  // is that its stats can be obtained from another thread during child heap iteration.
354  inline bool IsThreadSafe() const
355  {
356  return (Info.Desc.Flags & Heap_ThreadUnsafe) == 0;
357  }
358 
359  // Child heap lifetime is reference counted.
360  // These function need to be implemented when child heaps are supported.
361 
362  // Increments heap reference count; this function is primarily useful
363  // when enumerating heaps.
364  virtual void AddRef() = 0;
365 
366  // Releases this heap, deallocating it unless there are other references.
367  // Other references can come either from child heaps or multiple external
368  // references to the heap.
369  // Internal allocations are NOT considered references for heap lifetime.
370  // Release should only be called for heaps created with CreateHeap.
371  virtual void Release() = 0;
372 
373  // Marks allocation for automatic cleanup of heap. When this allocation
374  // is freed, the entire heap will be released. Allocation must belong
375  // to this heap, and should usually be the last item to be freed.
376  void ReleaseOnFree(void *ptr);
377 
378  // Assign heap to current thread causing ASSERTs if called for other thread
379  void AssignToCurrentThread();
380 
381  // *** Allocation API
382  //--------------------------------------------------------------------
383  virtual void* Alloc(UPInt size, const AllocInfo* info = 0) = 0;
384  virtual void* Alloc(UPInt size, UPInt align, const AllocInfo* info = 0) = 0;
385 
386  // Reallocates memory; this call does not maintain custom alignment specified
387  // during allocation.
388  virtual void* Realloc(void* oldPtr, UPInt newSize) = 0;
389  virtual void* ReallocAutoHeap(void* oldPtr, UPInt newSize) { return Realloc(oldPtr, newSize); }
390 
391  virtual void Free(void* ptr) = 0;
392 
393  // Allocate while automatically identifying heap and allocation id based on
394  // the specified address.
395  virtual void* AllocAutoHeap(const void *thisPtr, UPInt size,
396  const AllocInfo* info = 0) = 0;
397 
398 
399  virtual void* AllocAutoHeap(const void *thisPtr, UPInt size, UPInt align,
400  const AllocInfo* info = 0) = 0;
401 
402  // Determine which heap allocation belongs to.
403  // This function will ASSERT internally if the specified
404  // address does not come from one of allocated Scaleform heaps.
405  virtual MemoryHeap* GetAllocHeap(const void *thisPtr) = 0;
406 
407  // Returns the actual allocation size that can be safely used.
408  virtual UPInt GetUsableSize(const void* ptr) = 0;
409 
410  // Alloc and free directly from the system allocator. These functions
411  // are used only for debugging and/or visualization when it's necessary
412  // to allocate some large amount of memory with absolute minimal
413  // interference with the existing memory layout. Address alignment
414  // is only guaranteed to be SysAlloc::Info::MinAlign. These functions
415  // must be used with care!
416  virtual void* AllocSysDirect(UPInt size) = 0;
417  virtual void FreeSysDirect(void* ptr, UPInt size) = 0;
418 
419  // *** Statistics
420  //--------------------------------------------------------------------
421 
422  // Return the number of bytes allocated from the system
423  // and the number of actually allocated bytes in the heap.
424  // GetTotalUsedSpace() recursively iterates through all child
425  // heaps and sums up the total used space.
426  virtual UPInt GetFootprint() const = 0;
427  virtual UPInt GetTotalFootprint() const = 0;
428  virtual UPInt GetUsedSpace() const = 0;
429  virtual UPInt GetTotalUsedSpace() const = 0;
430  virtual void GetRootStats(RootStats* stats) = 0;
431 
432 
433  // DBG: To be removed in future.
434  // See MemVisitor::VisitingFlags for "flags" argument.
435  virtual void VisitMem(Heap::MemVisitor* visitor, unsigned flags) = 0;
436 
437  virtual void VisitRootSegments(Heap::SegVisitor* visitor) = 0;
438  virtual void VisitHeapSegments(Heap::SegVisitor* visitor) const = 0;
439 
440  virtual void SetTracer(HeapTracer* tracer) = 0;
441 
442  // Traverse all child heaps and dump memory leaks. If no debug info
443  // is present just report alive child heaps. Returns true if memory
444  // leaks have been detected.
445  bool DumpMemoryLeaks();
446 
447  void UltimateCheck();
448 
449  // Enumerates all of the child heaps, by calling HeapVisitor::Visit.
450  void VisitChildHeaps(HeapVisitor* visitor);
451  void LockAndVisit(HeapVisitor* visitor);
452  void CheckIntegrity();
453 
454  // The heap can hold a memory segment in its cache to reduce system
455  // memory thrashing. This function releases the cached segments from
456  // all heaps. It makes sense to call this function after some big
457  // unloads to return as much memory to the system as possible.
458  void ReleaseCachedMem();
459 
460 protected:
461  virtual void destroyItself() = 0;
462  virtual void ultimateCheck() = 0;
463  virtual void releaseCachedMem() = 0;
464  virtual bool dumpMemoryLeaks() = 0;
465  virtual void checkIntegrity() const = 0;
466  virtual void getUserDebugStats(RootStats* stats) const = 0;
467 
468  typedef List<MemoryHeap> ChildListType;
469 
470  UPInt SelfSize;
471  volatile unsigned RefCount;
472  UPInt OwnerThreadId;
473 
474  // Pointer to allocation that will cause this heap
475  // to be automatically released when freed.
476  void* pAutoRelease;
477 
478  HeapInfo Info;
479  ChildListType ChildHeaps;
480  mutable Lock HeapLock;
481  bool UseLocks;
482  bool TrackDebugInfo;
483 };
484 
485 } // Scaleform
486 
487 #endif
The Autodesk Navigation namespace.
Definition: gamekitcrowddispersion.cpp:17