summaryrefslogtreecommitdiff
path: root/inc/OSD_MAllocHook.hxx
blob: 4edd59bc9d5417c866f24583deebebc2903b70c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// File:	OSD_MAllocHook.hxx
// Created:	03.02.2011
// Author:	Mikhail SAZONOV
// Copyright:	Open CASCADE S.A.S. 2011

#ifndef _OSD_MAllocHook_HeaderFile
#define _OSD_MAllocHook_HeaderFile

#include <Standard_TypeDef.hxx>
#include <Standard_Mutex.hxx>
#include <stdio.h>

/**
 * This class provides the possibility to set callback for memory
 * allocation/deallocation.
 * On MS Windows, it works only in Debug builds. It relies on the
 * debug CRT function _CrtSetAllocHook (see MSDN for help).
 */
class OSD_MAllocHook
{
public:
  /**
   * Interface of a class that should handle allocation/deallocation events
   */
  class Callback
  {
  public:
    //! Allocation event handler
    /**
     * It is called when allocation is done
     * @param theSize
     *   the size of the memory block in bytes
     * @param theRequestNum
     *   the allocation order number of the memory block
     */
    virtual void AllocEvent
                   (size_t      theSize,
                    long        theRequestNum) = 0;

    //! Freeing event handler
    /**
     * It is called when the block is freed
     * @param theData
     *   the pointer to the user data section of the memory block
     * @param theSize
     *   the size of the memory block in bytes
     * @param theRequestNum
     *   the allocation order number of the memory block
     */
    virtual void FreeEvent
                   (void*       theData,
                    size_t      theSize,
                    long        theRequestNum) = 0;
  };

  /**
   * Implementation of the handler that collects all events
   * to the log file. It contains the method to generate the report
   * from the log file.
   */
  class LogFileHandler: public Callback
  {
  public:
    //! Constructor
    Standard_EXPORT LogFileHandler();

    //! Destructor
    Standard_EXPORT ~LogFileHandler();

    //! Create the file and start collecting events.
    //! Return false if the file with the given name cannot be created.
    Standard_EXPORT Standard_Boolean Open(const char* theFileName);

    //! Close the file and stop collecting events
    Standard_EXPORT void Close();

    //! Make synthesized report on the given log file.
    /**
     * Generate an easy to use report in the
     * new file with the given name, taking the given log file as input.
     * If theIncludeAlive is true then
     * include into the report the alive allocation numbers.
     */
    Standard_EXPORT static Standard_Boolean MakeReport
                   (const char* theLogFile,
                    const char* theOutFile,
                    const Standard_Boolean theIncludeAlive = Standard_False);

    Standard_EXPORT virtual void AllocEvent(size_t, long);
    Standard_EXPORT virtual void FreeEvent(void*, size_t, long);

  private:
    FILE*          myLogFile;
    Standard_Mutex myMutex;
    size_t         myBreakSize;
  };

  /**
   * Implementation of the handler that collects numbers of
   * allocations/deallocations for each block size directly in the memory.
   */
  class CollectBySize: public Callback
  {
  public:
    //! Constructor
    Standard_EXPORT CollectBySize();

    //! Destructor
    Standard_EXPORT ~CollectBySize();

    //! Reset the buffer and start collecting events.
    Standard_EXPORT void Reset();

    //! Write report in the given file.
    Standard_EXPORT Standard_Boolean MakeReport(const char* theOutFile);

    Standard_EXPORT virtual void AllocEvent(size_t, long);
    Standard_EXPORT virtual void FreeEvent(void*, size_t, long);

  private:
    struct Numbers
    {
      int nbAlloc;
      int nbFree;
      int nbLeftPeak;
      Numbers() : nbAlloc(0), nbFree(0), nbLeftPeak(0) {}
    };

    Standard_Mutex myMutex;
    Numbers*       myArray;
    size_t         myTotalLeftSize;
    size_t         myTotalPeakSize;
    size_t         myBreakSize;
  };

  //! Set handler of allocation/deallocation events
  /**
   * You can pass here any implementation. For easy start, you can try
   * with the predefined handler LogFileHandler, which static instance 
   * is returned by GetLogFileHandler().
   * To clear the handler, pass NULL here.
   */
  Standard_EXPORT static void SetCallback
                   (Callback* theCB);

  //! Get current handler of allocation/deallocation events
  Standard_EXPORT static Callback* GetCallback();

  //! Get static instance of LogFileHandler handler
  Standard_EXPORT static LogFileHandler* GetLogFileHandler();

  //! Get static instance of CollectBySize handler
  Standard_EXPORT static CollectBySize* GetCollectBySize();
};

#endif /* _OSD_MAllocHook_HeaderFile */