HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SYS_Memory.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: SYS_Memory.h ( SYS Library, C++)
7  *
8  * COMMENTS: Memory tracking utilities
9  */
10 
11 #ifndef __SYS_Memory__
12 #define __SYS_Memory__
13 
14 #include "SYS_API.h"
15 #include "SYS_Align.h"
16 #include "SYS_AtomicInt.h"
17 #include "SYS_Types.h"
18 
19 #include <cstddef>
20 
21 /// Memory Tracking
22 ///
23 /// This class provides a mechanism for tracking memory usage. If all
24 /// memory allocation and freeing is registered with this class, then
25 /// the memory footprint and resource usage can be tracked.
26 ///
27 /// There is a companion class at UT which allows for printing of the memory
28 /// statistics.
29 ///
30 /// An example of how to use this might be:
31 ///
32 /// enum {
33 /// MEM_DEBUG = 0,
34 /// MEM_TASK1,
35 /// MEM_TASK2,
36 /// MEM_MAX_TASKS
37 /// };
38 ///
39 /// static SYS_MemoryUser theMemoryUsers[MEM_MAX_TASKS] = {
40 /// SYS_MemoryUser("Debug),
41 /// SYS_MemoryUser("Task One"),
42 /// SYS_MemoryUser("Task Two"),
43 /// };
44 ///
45 /// static SYS_MemoryTable theMemoryTable(theMemoryUsers,
46 /// sizeof(theMemoryUsers)/sizeof(SYS_MemoryTable));
47 ///
48 /// int
49 /// main(int argc, char *argv[])
50 /// {
51 /// UT_WorkBuffer stats;
52 /// void *mem;
53 /// mem = SYS_Memory::Malloc(theMemoryTable, MEM_TASK1, 128);
54 /// mem = SYS_Memory::Realloc(theMemoryTable, MEM_TASK1, mem, 128, 256);
55 /// SYS_Memory::Free(theMemoryTable, MEM_TASK1, mem, 256);
56 /// UT_Memory::printTable(stats, theMemoryTable);
57 /// cout << stats.buffer();
58 /// return 0;
59 /// }
60 ///
61 
63 public:
64  SYS_MemoryUser(const char *label)
65  : myUsed(0)
66  , myPeak(0)
67  {
68  // WARNING: The label is a reference to the string. It's not hardened
69  myLabel = label;
70  }
71 
73  : myUsed(rhs.myUsed.relaxedLoad())
74  , myPeak(rhs.myPeak.relaxedLoad())
75  {
76  myLabel = rhs.myLabel;
77  }
78 
79  const char *getLabel() const { return myLabel; }
80  size_t getUsed() const { return myUsed.relaxedLoad(); }
81  size_t getPeak() const { return myPeak.relaxedLoad(); }
82 
83  void inc(size_t amount)
84  {
85  myPeak.maximum(myUsed.add(amount));
86  }
87  void dec(size_t amount)
88  {
89  myUsed.add(-amount);
90  }
91 
92  /// Forcibly set values - not typical usage, but required in some cases
93  void setUsedPeak(size_t used, size_t peak)
94  {
95  myUsed.exchange(used);
96  myPeak.exchange(peak);
97  }
98 
99 private:
100  const char *myLabel;
101  SYS_AtomicCounter myUsed;
102  SYS_AtomicCounter myPeak;
103 };
104 
106 public:
107  SYS_MemoryTable(SYS_MemoryUser *user_list, int number_of_users)
108  {
109  myTable = user_list;
110  mySize = number_of_users;
111  }
112 
113  SYS_MemoryUser &getUser(int index) { return myTable[index]; }
114  const SYS_MemoryUser &getUser(int index) const { return myTable[index]; }
115 
116  int entries() const { return mySize; }
117  size_t getUsed() const;
118  size_t getPeak() const;
119 
120  void inc(int user, size_t amount)
121  {
122  myTable[user].inc(amount);
123  }
124  void dec(int user, size_t amount)
125  {
126  myTable[user].dec(amount);
127  }
128 
129 private:
130  SYS_MemoryUser *myTable;
131  int mySize;
132 };
133 
135 public:
136  /// Allocate memory and track the usage.
137  /// This method will return a null pointer if the size requested is equal
138  /// to 0.
139  static void *Malloc(SYS_MemoryTable &table,
140  int which_entry,
141  size_t amount)
142  {
143  if (amount)
144  {
145  table.inc(which_entry, amount);
146  return malloc(amount);
147  }
148  return 0;
149  }
150  /// Allocate memory and track the usage. The memory will filled with zero.
151  /// This method will return a null pointer if the size requested is equal
152  /// to 0.
153  static void *Calloc(SYS_MemoryTable &table,
154  int which_entry,
155  size_t amount)
156  {
157  if (amount)
158  {
159  table.inc(which_entry, amount);
160  return calloc(1, amount);
161  }
162  return 0;
163  }
164  /// Re-allocate a previously allocated block. This method handles
165  /// the case where the initial block has not been allocated (i.e. is a
166  /// null pointer).
167  /// This method will return a null pointer if the new_amount size requested
168  /// is equal to 0.
170  int which_entry,
171  void *original_memory,
172  size_t old_amount,
173  size_t new_amount)
174  {
175  void *mem;
176  if (new_amount)
177  {
178  if (original_memory)
179  {
180  // Do it as two separate operations since size_t
181  // may be an unsigned and taking the delta may
182  // cause an overflow.
183  table.dec(which_entry, old_amount);
184  table.inc(which_entry, new_amount);
185  mem = realloc(original_memory, new_amount);
186  }
187  else
188  {
189  table.inc(which_entry, new_amount);
190  mem = malloc(new_amount);
191  }
192  }
193  else
194  {
195  mem = 0;
196  if (original_memory)
197  {
198  table.dec(which_entry, old_amount);
199  free(original_memory);
200  }
201  }
202  return mem;
203  }
204 
205  /// Free an allocated block (tracking the memory usage).
206  /// If a null pointer is passed in, no tracking will be done. Thus, it's
207  /// safe to pass in a non-zero size without a valid pointer (and not
208  /// destroy the tracking process).
209  static void Free(SYS_MemoryTable &table,
210  int which_entry,
211  void *memory,
212  size_t amount)
213  {
214  if (memory)
215  {
216  table.dec(which_entry, amount);
217  free(memory);
218  }
219  }
220 
221  /// Track a memory acquisition that wasn't performed by this class.
223  int which_entry,
224  size_t amount)
225  {
226  table.inc(which_entry, amount);
227  }
228  /// Track a memory free that wasn't performed by this class.
230  int which_entry,
231  size_t amount)
232  {
233  table.dec(which_entry, amount);
234  }
235 };
236 
237 /// When implementing in a different library, the following macro can be used
238 /// to implement a localized interface. For example, we might have
239 /// SYS_MEMORY_SUBCLASS(, GU, theGUMemoryTable)
240 /// or
241 /// class GU_Memory {
242 /// public:
243 /// SYS_MEMORY_SUBCLASS(static, GU, myMemoryTable)
244 /// private:
245 /// static SYS_MemoryTable myMemoryTable;
246 /// };
247 ///
248 #define SYS_MEMORY_SUBCLASS(STATIC, prefix, table) \
249  STATIC void *prefix##Malloc(int i, size_t amount) \
250  { return SYS_Memory::Malloc(table, i, amount); } \
251  STATIC void *prefix##Calloc(int i, size_t amount) \
252  { return SYS_Memory::Calloc(table, i, amount); } \
253  STATIC void *prefix##Realloc(int i, void *m, size_t o, size_t n) \
254  { return SYS_Memory::Realloc(table, i, m, o, n); } \
255  STATIC void prefix##Free(int i, void *m, size_t amount) \
256  { SYS_Memory::Free(table, i, m, amount); } \
257  STATIC void prefix##acquire(int i, size_t amount) \
258  { SYS_Memory::acquire(table, i, amount); } \
259  STATIC void prefix##release(int i, size_t amount) \
260  { SYS_Memory::release(table, i, amount); } \
261  static inline SYS_MemoryTable &prefix##getTable() { return table; }
262 
263 ///
264 /// Convenience function to print memory in a consistent format (i.e. 12.3 KB).
265 /// To print "18446744073709551616.00 MB" requires 27 characters. There are 5
266 /// extra characters for good measure in SYS_MEMPRINTSIZE
267 #define SYS_MEMPRINTSIZE 32
268 SYS_API void SYSprintMemory(char buf[SYS_MEMPRINTSIZE], int64 memory,
269  int field_width=-1);
270 
271 #endif
SYS_API void SYSprintMemory(char buf[SYS_MEMPRINTSIZE], int64 memory, int field_width=-1)
static void release(SYS_MemoryTable &table, int which_entry, size_t amount)
Track a memory free that wasn't performed by this class.
Definition: SYS_Memory.h:229
void dec(size_t amount)
Definition: SYS_Memory.h:87
SYS_MemoryUser(const SYS_MemoryUser &rhs)
Definition: SYS_Memory.h:72
const SYS_MemoryUser & getUser(int index) const
Definition: SYS_Memory.h:114
static void Free(SYS_MemoryTable &table, int which_entry, void *memory, size_t amount)
Definition: SYS_Memory.h:209
SYS_MemoryUser & getUser(int index)
Definition: SYS_Memory.h:113
GLuint GLsizei const GLchar * label
Definition: glcorearb.h:2545
static void * Realloc(SYS_MemoryTable &table, int which_entry, void *original_memory, size_t old_amount, size_t new_amount)
Definition: SYS_Memory.h:169
long long int64
Definition: SYS_Types.h:116
static void * Calloc(SYS_MemoryTable &table, int which_entry, size_t amount)
Definition: SYS_Memory.h:153
void inc(int user, size_t amount)
Definition: SYS_Memory.h:120
void setUsedPeak(size_t used, size_t peak)
Forcibly set values - not typical usage, but required in some cases.
Definition: SYS_Memory.h:93
size_t getUsed() const
Definition: SYS_Memory.h:80
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
SYS_MemoryUser(const char *label)
Definition: SYS_Memory.h:64
SYS_MemoryTable(SYS_MemoryUser *user_list, int number_of_users)
Definition: SYS_Memory.h:107
static void acquire(SYS_MemoryTable &table, int which_entry, size_t amount)
Track a memory acquisition that wasn't performed by this class.
Definition: SYS_Memory.h:222
GLuint index
Definition: glcorearb.h:786
int entries() const
Definition: SYS_Memory.h:116
static void * Malloc(SYS_MemoryTable &table, int which_entry, size_t amount)
Definition: SYS_Memory.h:139
const char * getLabel() const
Definition: SYS_Memory.h:79
size_t getPeak() const
Definition: SYS_Memory.h:81
#define SYS_API
Definition: SYS_API.h:11
GLenum GLsizei GLenum GLenum const void * table
Definition: glew.h:4970
void inc(size_t amount)
Definition: SYS_Memory.h:83
void dec(int user, size_t amount)
Definition: SYS_Memory.h:124
#define SYS_MEMPRINTSIZE
Definition: SYS_Memory.h:267