gwnavruntime/kernel/SF_MemoryHeap.h Source File

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