3 This file is part of the Free Pascal run time library
.
4 Copyright (c
) 1999-2000 by Pierre Muller
,
5 member of the Free Pascal development team
.
7 Profiling support
for Go32V2
9 See the file COPYING
.FPC
, included
in this distribution
,
10 for details about the copyright
.
12 This program is distributed
in the hope that it will be useful
,
13 but WITHOUT ANY WARRANTY
; without even the implied warranty of
14 MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE
.
16 **********************************************************************
19 {$S- do not use stackcheck here
.. PM
}
22 {$message you can
not compile profile unit with profiling
}
31 low
,high
,nbytes
: longint
;
34 { entry of a GPROF type file
}
38 from
,_to
,count
: longint
;
41 { internal form
- sizeof(MTAB
) is
4096 for efficiency
}
44 calls
: array
[0..340] of MTABE
;
49 mcount_skip
: longint
= 1;
55 oldexitproc
: pointer
;
57 { called by functions
. Use the pointer it provides to cache the last used
58 MTABE
, so that repeated calls to
/from the same pair works quickly
-
75 djgpp_old_timer
: tseginfo
;external name
'___djgpp_old_timer';
76 start
: longint
;external name
'start';
77 _etext
: longint
;external name
'_etext';
81 procedure djgpp_timer_hdlr
;external name
'___djgpp_timer_hdlr';
83 procedure
sbrk_getmem(var p
: pointer
;size
: longint
);
86 system
.getmem(p
,size
);
90 { problem how to avoid mcount calling itself
!! }
91 procedure mcount
; [public
, alias : 'MCOUNT'];
93 ebp contains the frame of
mcount (ebp
) the frame of
calling (to_
)
94 ((ebp
)) the frame of from
98 i
,to_
,ebp
,from
,mtabi
: longint
;
116 if (to_
> endtext
) or (from
> endtext
) then
118 if ((cache
<>nil) and (cache^
.from
=from
) and (cache^
._to
=to_
)) then
120 { cache paid off
- works quickly
}
129 { no cache hit
- search all mtab tables
for a match
, or an empty slot
}
136 if m^
.calls
[i
].from
=0 then
138 { empty slot
- end of table
}
142 if ((m^
.calls
[i
].from
= from
) and (m^
.calls
[i
]._to
= to_
)) then
144 { found a match
- bump count
and return }
145 inc(m^
.calls
[i
].count
);
146 cache
:=@
(m^
.calls
[i
]);
159 { found an empty
- fill it
in }
160 mtab^
.calls
[mtabi
].from
:= from
;
161 mtab^
.calls
[mtabi
]._to
:= to_
;
162 mtab^
.calls
[mtabi
].count
:= 1;
163 cache
:= @
(mtab^
.calls
[mtabi
]);
171 { lob off another page of memory
and initialize the new table
}
172 { problem here
: getmem is
not reentrant yet
!! PM
}
173 { lets hope that a direct call to sbrk correct this
}
174 sbrk_getmem(m
,sizeof(M_TAB
));
175 fillchar(m^
, sizeof(M_TAB
),#0);
178 m^
.calls
[0].from
:= from
;
179 m^
.calls
[0]._to
:= to_
;
180 m^
.calls
[0].count
:= 1;
181 cache
:= @
(m^
.calls
[0]);
193 old_timer
: tseginfo
;
197 reload
: longint
; {=0}
199 function
mcount_tick(x
: longint
) : longint
;
203 if mcount_skip
=0 then
205 bin
:= djgpp_exception_state^
.__eip
;
206 if (djgpp_exception_state^
.__cs
=get_cs
) and (bin
>= starttext
) and (bin
<= endtext
) then
208 bin
:= (bin
- starttext
) div
16;
212 inc(invalid_mcount_call
);
222 ___djgpp_timer_countdown
:longint;external name
'___djgpp_timer_countdown';
224 function
timer(x
: longint
) : longint
;
227 ___djgpp_timer_countdown
:=RELOAD
;
228 timer
:=mcount_tick(x
);
233 procedure mcount_write
;
235 this is called during program exit
243 signal(SIGTIMR
,@SIG_IGN);
244 signal(SIGPROF
,@SIG_IGN);
245 set_pm_interrupt($8,old_timer
);
247 exitproc
:=oldexitproc
;
248 writeln(stderr,'Writing profile output');
249 writeln(stderr,'histogram length = ',histlen
);
250 writeln(stderr,'Nb of double calls = ',doublecall
);
251 if invalid_mcount_call
>0 then
252 writeln(stderr,'nb of invalid mcount : ',invalid_mcount_call
,'/',mcount_nb
)
254 writeln(stderr,'nb of mcount : ',mcount_nb
);
255 assign(f
,'gmon.out');
257 blockwrite(f
, h
, sizeof(header
));
258 blockwrite(f
, histogram^
, histlen
);
264 if (m^
.calls
[i
].from
= 0) then
266 blockwrite(f
, m^
.calls
[i
],sizeof(MTABE
));
268 if m^
.calls
[i
].count
>0 then
269 writeln(stderr,' 0x',hexstr(m^
.calls
[i
]._to
,8),' called from ',hexstr(m^
.calls
[i
].from
,8),
270 ' ',m^
.calls
[i
].count
,' times');
279 procedure mcount_init
;
281 this is called to initialize profiling before the program starts
284 procedure set_old_timer_handler
;
286 djgpp_old_timer
:=Old_Timer
;
290 starttext
:=longint(@start);
291 endtext
:=longint(@_etext);
294 histlen
:= ((h
.high-h
.low
) div
16) * 2; { must be even
}
295 h
.nbytes
:= sizeof(header
) + histlen
;
296 getmem(histogram
,histlen
);
297 fillchar(histogram^
, histlen
,#0);
299 oldexitproc
:=exitproc
;
300 exitproc
:=@mcount_write;
302 { here
, do whatever it takes to initialize the timer interrupt
}
303 signal(SIGPROF
,@mcount_tick);
304 signal(SIGTIMR
,@timer);
306 get_pm_interrupt($8,old_timer
);
307 set_old_timer_handler
;
309 writeln(stderr,'ori pm int8 '+hexstr(old_timer
.segment
,4)+':'+hexstr(longint(old_timer
.offset
),8));
312 new_timer
.segment
:=get_cs
;
313 new_timer
.offset
:=@djgpp_timer_hdlr;
316 writeln(stderr,'new pm int8 '+hexstr(new_timer
.segment
,4)+':'+hexstr(longint(new_timer
.offset
),8));
319 set_pm_interrupt($8,new_timer
);
321 ___djgpp_timer_countdown
:=RELOAD
;
331 Revision
1.1 2002/02/19 08:25:13 sasu
334 Revision
1.1 2000/07/13 06:30:39 michael
337 Revision
1.7 2000/03/28 10:06:19 pierre
340 Revision
1.6 2000/03/20 13:09:07 pierre
343 Revision
1.5 2000/02/09 16:59:29 peter
346 Revision
1.4 2000/01/07 16:41:32 daniel
349 Revision
1.3 2000/01/07 16:32:23 daniel
350 * copyright
2000 added