~hikiko/nux/arb-srgba-shader

« back to all changes in this revision

Viewing changes to NuxCore/Memory/NMemoryDebugHook.h

  • Committer: Neil Jagdish Patel
  • Date: 2010-09-01 19:25:37 UTC
  • Revision ID: neil.patel@canonical.com-20100901192537-mfz7rm6q262pewg6
Import and build NuxCore

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifndef NMEMORYDEBUGHOOK_H
 
2
#define NMEMORYDEBUGHOOK_H
 
3
 
 
4
NAMESPACE_BEGIN
 
5
 
 
6
#define INL_NB_ALLOCATOR_MAX  127
 
7
/// MemDebug class is a layer that sits on memory allocators, and used to help debugging memory management
 
8
/*! The Memory Debugger is doing a lot of verification on every allocation/free action.
 
9
The idea is to allocate more than requested (32 bytes for the header + 4 trailing bytes = 36 bytes)
 
10
to keep information on the current memory block. This header contains:
 
11
- 2 Pointers for insertion in a double linked list
 
12
- The Size of the original block allocated
 
13
- The current Status of the block
 
14
- The Allocator ID that from which the block belong
 
15
- The filename & Line number in the file where the block has been allocated (and then freed)
 
16
- The Object type
 
17
- A header Checksum
 
18
 
 
19
The Memory Debugger keeps track of all the block allocated in a double linked list. That's the way
 
20
used to track leak at run-time. There is one distinct list per allocator, so it's possible to verify
 
21
leak for a specific allocator, or for all the system.
 
22
On allocation, the real size requested to the allocator is bigger to keep the header at the beginning
 
23
of the memory block. The size of the header is always a multiple of GEAR_HW_MEM_ALIGN.
 
24
The header is initialized, the checksum computed, and the buffer is filled with a known value. This will
 
25
be used when the block will be freed to evaluate the percentage of the block that has been used. This system
 
26
isn't 100% bullet proof, since there is a small percentage of cases where memory wasted will be detected
 
27
and will not be in reality (if the user write in the buffer the same pattern as used as filling value).
 
28
There is also 4 extra bytes added at the end of the buffer as a stopper, to ensure that no buffer overflow
 
29
occured. The pointer returned is then a value pointing right after the header, and this value is guaranteed
 
30
to be aligned.
 
31
 
 
32
During run time, a buffer integrity can be verified (Verify alignment, header checksum, allocator matching
 
33
and bottom flag integrity). A leak detection can be performed, that consist of simply listing all buffers
 
34
currently still allocated.
 
35
*/
 
36
class MemDebug : public MemoryHook
 
37
{
 
38
    /// MemDebug is a Global Object
 
39
    INL_DECLARE_GLOBAL_OBJECT(MemDebug, NGlobalSingletonInitializer);
 
40
 
 
41
public :
 
42
    typedef enum {  Invalid         = -1, 
 
43
        Unaligned       = -2, 
 
44
        Corrupted       = -3, 
 
45
        Overflow        = -4, 
 
46
        WrongAllocator  = -5, 
 
47
        DoubleFree      = -6 
 
48
    } Err;
 
49
 
 
50
    /// SetAllocFailure allows to simulate a failure in allocation.
 
51
    /*! This function available only when the debugger is enabled, allows to simulate allocation
 
52
    failure to test user code. The failure is set per Allocator. Any call to Alloc/Realloc/New will
 
53
    fail for [NbFailure] allocation in [Delay] calls. Failure sequence aren't queued, so any call
 
54
    to SetAllocFailure will change the previous one. To disable any failure simulation, just
 
55
    call SetAllocFailure(Allocator, 0, 0) (default params).
 
56
    \param Allocator    The allocator that will simulate an alloc fail
 
57
    \param Delay        The number of call To Alloc before the failure. 0 = Next call
 
58
    \param NbFailure    The number of call to Alloc that must fail in a row.
 
59
    \return             None
 
60
    \sa GEAR_ALLOC(), GEAR_REALLOC()
 
61
    */
 
62
    void SetAllocFailure(   const NMemoryAllocatorInterface&     Allocator, 
 
63
        unsigned                Delay = 0, 
 
64
        unsigned                NbFailure = 0);
 
65
 
 
66
    /// Returns the number of buffers still allocated in the specified allocator
 
67
    /*! \param AllocId  The allocator we're gonna verify
 
68
    \param Verbose  When true, will send a warning on the debug device if a leak is detected
 
69
    \return The number of buffer still allocated
 
70
    \sa VerifyLeakAll(), GEAR_ALLOC(), GEAR_FREE()
 
71
    */
 
72
    unsigned VerifyLeak(NMemoryAllocatorInterface::id AllocId, bool Verbose = true);
 
73
 
 
74
    /// Returns the number of buffers still allocated in all allocators
 
75
    /*! \param Verbose  When true, will send a warning on the debug device if a leak is detected
 
76
    \return The total number of buffer still allocated in all buffers
 
77
    \sa VerifyLeak(), GEAR_ALLOC(), GEAR_FREE()
 
78
    */
 
79
    unsigned VerifyLeakAll(bool Verbose = true);
 
80
 
 
81
    /// Verify buffer status for the specified allocator
 
82
    /*! Here's a list of problems detected on a problematics buffers:
 
83
    - Pointer position (Null & Alignment)
 
84
    - Double Free
 
85
    - Header integrity (Overflow problem slightly before the pointer)
 
86
    - Verify allocator matching (The allocator specified is the same as recorded when allocated)
 
87
    - Bottom flag (To detect overflow)
 
88
    \param AllocId  The allocator we're gonna verify
 
89
    \param Verbose  When true, will send a warning on the debug device if a problem is detected
 
90
    \return An error code (see MemDebug::Err) or 0 if the buffer is sound.
 
91
    \sa VerifyLeakAll(), GEAR_ALLOC(), GEAR_FREE()
 
92
    */
 
93
    int  VerifyBuffer(NMemoryAllocatorInterface::id AllocId, bool Verbose = true);
 
94
 
 
95
    /// Verify buffer status for all allocators
 
96
    /*! \param Verbose  When true, will send a warning on the debug device if a problem is detected
 
97
    \return The number of allocators that contains problematics buffers
 
98
    \sa VerifyBufferAll()
 
99
    */
 
100
    unsigned  VerifyBufferAll(bool Verbose = true);
 
101
 
 
102
    /// Verify buffer status for the specified allocator and the specified buffer pointed on by pBuf
 
103
    /*! Here's a list of problems detected on a problematics buffers:
 
104
    - Pointer position (Null & Alignment)
 
105
    - Double Free
 
106
    - Header integrity (Overflow problem slightly before the pointer)
 
107
    - Verify allocator matching (The allocator specified is the same as recorded when allocated)
 
108
    - Bottom flag (To detect overflow)
 
109
    \param pBuf Pointer to the memory block
 
110
    \return Block status (see MemDebug::Err) or 0 if the buffer is sound.
 
111
    */
 
112
    int VerifyPointer(void* pBuf);
 
113
 
 
114
    /// Returns the unused memory in an allocated memory block
 
115
    /*! When allocated, a block is filled with a known pattern. Starting from the end of the block, 
 
116
    we can trace back the pattern until the first byte changed, and evaluate the number of bytes
 
117
    "wasted"
 
118
    \param pData A pointer on a block of data allocated
 
119
    \return The number of bytes unused (wasted)
 
120
    */
 
121
    virtual unsigned GetWastedMemory(const void* pData) const;
 
122
 
 
123
    /// Returns the logagent identifier for the memory debugger
 
124
    static const char* GetLogId(void)
 
125
    { 
 
126
        return "MemoryDebugger"; 
 
127
    }
 
128
 
 
129
    /// Reset the Leak Threshold value. All allocations done before will not be considered as leak
 
130
    t_u32 ResetLeakThreshold(void)
 
131
    { 
 
132
        t_u32 oldValue = m_LeakThresholdSeqNo;
 
133
        m_LeakThresholdSeqNo = m_SequenceNoServer; 
 
134
        return oldValue;
 
135
    }
 
136
 
 
137
    /// Sets the leak threshold value. All allocations made before this sequence number won't be considered as leaks
 
138
    /// Set value to 0 to get all unfreed allocations
 
139
    void SetLeakThreshold(t_u32 seqNo)
 
140
    {
 
141
        m_LeakThresholdSeqNo = seqNo; 
 
142
    }
 
143
 
 
144
    virtual void* Alloc(    int          OpId, 
 
145
        unsigned            Size, 
 
146
        NMemoryAllocatorInterface&       Allocator, 
 
147
        const void*         pParent, 
 
148
        const char*         pId,
 
149
        const char*         pObjType,
 
150
        t_u32               LineNo,
 
151
        const TCHAR*        pFileName);
 
152
 
 
153
    virtual void* AllocAligned(int       OpId, 
 
154
        unsigned            Size, 
 
155
        unsigned            Alignment,
 
156
        NMemoryAllocatorInterface&       Allocator, 
 
157
        const void*         pParent, 
 
158
        const char*         pId,
 
159
        const char*         pObjType,
 
160
        t_u32               LineNo,
 
161
        const TCHAR*        pFileName);
 
162
 
 
163
    virtual void* Realloc(void*               pOldPtr,
 
164
        unsigned            NewMemSizeInByte, 
 
165
        NMemoryAllocatorInterface&       Allocator, 
 
166
        t_u32               LineNo,
 
167
        const TCHAR*         pFileName);
 
168
 
 
169
    virtual void* ReallocAligned(void*        pOldPtr,
 
170
        unsigned            NewMemSizeInByte, 
 
171
        unsigned            Alignment, 
 
172
        NMemoryAllocatorInterface&       Allocator, 
 
173
        t_u32               LineNo,
 
174
        const TCHAR*         pFileName);
 
175
 
 
176
    virtual void Free(int   OpId,
 
177
        void*               pData, 
 
178
        NMemoryAllocatorInterface&       Allocator,
 
179
        t_u32               LineNo,
 
180
        const TCHAR*         pFileName);
 
181
    virtual void FreeMarker(void*               pMarker, 
 
182
        MemStackInterface&  StackAllocator, 
 
183
        t_u32               LineNo, 
 
184
        const TCHAR*         pFileName);
 
185
    virtual t_u32 GetAllocatedSize(void* pData,                                         
 
186
        NMemoryAllocatorInterface&   Allocator, 
 
187
        t_u32*              pRetHeaderSize) const;
 
188
 
 
189
    virtual void AllocatorDestruction(NMemoryAllocatorInterface& Allocator);
 
190
 
 
191
    virtual unsigned GetDebugOverHead(unsigned alignment) const;
 
192
    /*
 
193
    /// We use the default behavior of theses virtual functions. It's intentionally NOT implemented
 
194
    virtual void* GetMarker(MemStackInterface&  StackAllocator, 
 
195
    t_u32                 LineNo, 
 
196
    const TCHAR*         pFileName);        
 
197
    */
 
198
 
 
199
    t_u32 GetAllocationNumber(const void *pData) const;
 
200
 
 
201
    // Callback used by the client for validation
 
202
    typedef void (*OnAllocCallbackType)(void * userAddr, size_t size);
 
203
    typedef void (*OnFreeCallbackType) (void * userAddr, size_t size);
 
204
    void SetOnAllocCallback(OnAllocCallbackType callback);
 
205
    void SetOnFreeCallback(OnFreeCallbackType callback);
 
206
 
 
207
private:
 
208
    void            FreeBlock(          int                 OpId,
 
209
        void*               pData,
 
210
        NMemoryAllocatorInterface&       Allocator,
 
211
        t_u32                 LineNo,
 
212
        const TCHAR*         pFileName);
 
213
    int             VerifyBlock(        void*               pBuf,
 
214
        NMemoryAllocatorInterface::id    AllocId,
 
215
        bool                Verbose = true);
 
216
    bool            VerifyAllocFailure( NMemoryAllocatorInterface::id    AllocId);
 
217
    t_u32             CalculateDebugSize( t_u32                 Size, t_u32 Alignment) const;
 
218
    void*           SecondStageAlloc(   void*               pBuffer,
 
219
        int                 OpId,
 
220
        unsigned            Size, 
 
221
        unsigned            Alignment,
 
222
        NMemoryAllocatorInterface::id    AllocId,                                                                                         
 
223
        t_u32                 LineNo,
 
224
        const TCHAR*         pFileName,
 
225
        t_u32                 sequenceNo);       
 
226
    void            VerifyMemoryWasted( const void* pBuf);
 
227
 
 
228
    class dbg_header
 
229
    {    
 
230
    public:
 
231
        t_u32             FrontFlag;      // Flag at the beginning of the packet
 
232
        NListNoDyn<dbg_header>::Node m_Node;
 
233
        //INL_NLISTNODYN_NODE(dbg_header); // Double linked list header
 
234
    public:
 
235
        t_u32             Size;           // Size of the user buffer
 
236
        t_u16             LineNo;         // Line number from allocator
 
237
        t_u8              Status;         // Status of block
 
238
        t_u8              AllocId;        // Allocator Identifier
 
239
        const TCHAR*      pFileName;      // Allocator's FileName
 
240
        t_u32             SequenceNo;     // Sequential number
 
241
        t_u32             Checksum;       // Header checksum
 
242
    };
 
243
 
 
244
    class data_per_allocator
 
245
    {       
 
246
    public:
 
247
        NListNoDyn<dbg_header>   AllocatedList;  // List of allocated block
 
248
        unsigned                FailureDelay;   // Delay before next failure
 
249
        unsigned                FailureCount;   // Number of successive failure
 
250
    };
 
251
 
 
252
    data_per_allocator  m_AllocatorTbl[INL_NB_ALLOCATOR_MAX];
 
253
    NCriticalSection    m_Lock;
 
254
    t_u32               m_SequenceNoServer;     // On every alloc we increase this counter
 
255
    t_u32               m_LeakThresholdSeqNo;   // All alloc before this value is not considered Leak
 
256
 
 
257
    OnAllocCallbackType     OnAllocCallback; // The pointer on client AllocCallback 
 
258
    OnFreeCallbackType      OnFreeCallback;  // The pointer on client FreeCallback
 
259
};
 
260
 
 
261
NAMESPACE_END
 
262
 
 
263
#endif // NMEMORYDEBUGHOOK_H