1 % memusage.w
-- Program to check amount of memory used by other programs.
3 % This program is public domain
, but if you combine it with GPL program
,
4 % the combination is licensed by GPL.
7 \emergencystretch
=\hsize
12 @
*Introduction. This program is used to trace usage of dynamic memory of
13 another program. It is not usable with all programs
; it is meant to be
14 used with \TeX nicard
, although you might modify it to work with other
19 @
<Global variables@
>@
;
21 @
<Macros to override standard functions@
>@
;
22 #include
"memusage_other_program.c"
24 @ Some include files are used here since they are used in the rest of the
33 @
*Initialization. A log file is opened so that the information about
34 dynamic memory can be logged. Also
, it is kept track of how much memory is
35 being used in total. Another thing which must be kept track of is the list
36 of allocated pointers so that when |realloc| and |free| is used
, it knows
37 what memory is becoming unused.
41 size_t memusage_total
=0;
43 size_t
*memusage_sizes
;
45 @ @
<Procedure codes@
>=
46 int main
(int argc
,char
**argv
) {
47 memusage_fp
=fopen
("memusage.log","w");
49 @
<Initialize |memusage_list| and |memusage_sizes|@
>;
50 fprintf
(memusage_fp
,"Time %u: Program started\n",(unsigned int
)clock
());
51 return your_main
(argc
,argv
);
54 @ The function |your_main| is the main function of the other program. It
55 will be a macro here to override it.
57 @
<Macros to override standard functions@
>=
58 #define main @
!your_main
60 @ Null pointers in |memusage_list| represent unused fields
, while the
61 pointer to |
&memusage_list| itself is used as the terminator. There is
62 also |memusage_sizes| which are sizes of data in |memusage_list|.
64 @
<Initialize |memusage_list| and |memusage_sizes|@
>= {
66 memusage_list
=malloc
(16*sizeof
(void
*));
67 memusage_sizes
=malloc
(16*sizeof
(size_t
));
68 for
(i
=0;i
<16;i
++) memusage_list
[i
]=memusage_sizes
[i
]=0;
69 memusage_list
[15]=&memusage_list;
72 @
*Usage Tracking. Memory usage is tracked by a function called
73 |memusage_track| which looks in |memusage_list| and also does logging of
77 void memusage_track
(void
*ptr
,void
*newptr
,size_t size
,char
*message
) {
78 int i
; // Where is |ptr| found?
79 if
(!ptr
&& !newptr) @<Log the empty pointer and |return|@>;
80 @
<Check where |ptr| is found in the list@
>;
81 if
(memusage_list
[i
]==&memusage_list)
82 @
<Allocate more memory for |memusage_list| and |memusage_sizes|@
>;
83 @
<Update the memory usage arrays and total@
>;
84 @
<Log the memory usage and message to the file@
>;
87 @ @
<Log the empty pointer and |return|@
>= {
88 fprintf
(memusage_fp
,"NULL [%08X] -- %s\n",(int
)size
,message
);
92 @ @
<Check where |ptr| is found in the list@
>= {
93 for
(i
=0;memusage_list
[i
]!=&memusage_list;i++) {
94 if
(memusage_list
[i
]==ptr
) break
;
98 @ @
<Allocate more memory for |memusage_list| and |memusage_sizes|@
>= {
100 memusage_list
=realloc
(memusage_list
,i
*sizeof
(void
*)*2);
101 memusage_sizes
=realloc
(memusage_sizes
,i
*sizeof
(size_t
)*2);
102 for
(j
=i
;j
<i
*2;j
++) memusage_list
[j
]=memusage_sizes
[j
]=0;
103 memusage_list
[j-1
]=&memusage_list;
106 @ @
<Update the memory usage arrays and total@
>= {
107 memusage_total
+=size-memusage_sizes
[i
];
108 memusage_list
[i
]=newptr
;
109 memusage_sizes
[i
]=size
;
112 @ @
<Log the memory usage and message to the file@
>= {
113 fprintf
(memusage_fp
,"[%08X] %08X %08X [%08X] -- %s\n",
114 i
,(int
)ptr
,(int
)newptr
,(int
)size
,message
);
115 fprintf
(memusage_fp
,"Time %u: Total %08X\n",(unsigned int
)clock
(),
119 @ There is one more thing
, so that the program can make up its own log
122 @d memusage_log
(_text
,_arg1
)
123 fprintf
(memusage_fp
,"Time %u: %s [%08X]\n",(unsigned int
)clock
(),
126 @
*Overrides. Now to override standard functions so that they can be
127 tracked. Most of these are very simple.
129 The first one is |malloc|.
132 void
*my_malloc
(size_t size
) {
134 memusage_track
(0,p
,size
,"malloc");
141 void my_free
(void
*ptr
) {
143 memusage_track
(ptr
,0,0,"free");
146 @ Next comes |realloc|.
149 void
*my_realloc
(void
*ptr
,size_t size
) {
150 void
*p
=realloc
(ptr
,size
);
151 memusage_track
(ptr
,p
,size
,"realloc");
155 @ Now comes |strdup|
, which is a bit more complicated than the others
, but
159 char
*my_strdup
(const char
*s1
) {
161 memusage_track
(0,p
,strlen
(s1
)+1,"strdup");
165 @ Now let's override them by macros so that the other programs will call
166 our functions instead
, and that they will be traced.
168 @
<Macros to override standard functions@
>=
169 #define malloc my_malloc
171 #define realloc my_realloc
172 #define strdup my_strdup