Gamma and other image manipulation commands
[TeXnicard.git] / util / memusage.w
blobcb6ddcbd083d3dca4dbc51ad96a3307d9cee5aa8
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.
6 \def\title{MEMUSAGE}
7 \emergencystretch=\hsize
9 @s FILE int
10 @s size_t int
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
15 programs too.
18 @<Include files@>@;
19 @<Global variables@>@;
20 @<Procedure codes@>;
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
25 program.
27 @<Include files@>=
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
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.
39 @<Global variables@>=
40 FILE*memusage_fp;
41 size_t memusage_total=0;
42 void**memusage_list;
43 size_t*memusage_sizes;
45 @ @<Procedure codes@>=
46 int main(int argc,char**argv) {
47 memusage_fp=fopen("memusage.log","w");
48 @.memusage.log@>
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|@>= {
65 int i;
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
74 the information.
76 @<Procedure codes@>=
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);
89 return;
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|@>= {
99 int j;
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(),
116 memusage_total);
119 @ There is one more thing, so that the program can make up its own log
120 messages.
122 @d memusage_log(_text,_arg1)
123 fprintf(memusage_fp,"Time %u: %s [%08X]\n",(unsigned int)clock(),
124 _text,_arg1);
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|.
131 @<Procedure codes@>=
132 void*my_malloc(size_t size) {
133 void*p=malloc(size);
134 memusage_track(0,p,size,"malloc");
135 return p;
138 @ Now |free|.
140 @<Procedure codes@>=
141 void my_free(void*ptr) {
142 free(ptr);
143 memusage_track(ptr,0,0,"free");
146 @ Next comes |realloc|.
148 @<Procedure codes@>=
149 void*my_realloc(void*ptr,size_t size) {
150 void*p=realloc(ptr,size);
151 memusage_track(ptr,p,size,"realloc");
152 return p;
155 @ Now comes |strdup|, which is a bit more complicated than the others, but
156 not by much.
158 @<Procedure codes@>=
159 char*my_strdup(const char*s1) {
160 char*p=strdup(s1);
161 memusage_track(0,p,strlen(s1)+1,"strdup");
162 return p;
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
170 #define free my_free
171 #define realloc my_realloc
172 #define strdup my_strdup
174 @*Index.