Michael Van Canneyt wrote:
On Tue, 10 Nov 2009, Schatzl Thomas wrote:
The main reason for this slowness is that that implementation (of
mine) reads debug info byte-by-byte from the input stream using
blockread(). I think this I/O the main performance bottleneck.
At that time I did not bother improving this since it is sufficient
for my purposes. I did not test with very large debug infos because
on my development platform Lazarus does not work >:)
Improving upon that should be trivial, all reading from the debug
input has been encapsuled in the two ReadNext() methods in the file
mentioned. It should be easy to make them to read from a (static?)
buffer that is filled blockwise; note that a static buffer may give
headaches for MT programs, and you are strongly discouraged to do
memory allocation during crashes...
By making the buffer a threadvar, this should not be an issue ?
I was glad to read your answer, because I was having the same problem
as Martin.
I ended up by simply disabling the stack trace.
Ok , I have created a patch. And it does the trick. Without it dumping
about 15 frames took 30secs. With the patch it stays below 1 sec (too
fast to measure).
The patch only uses a buffer of 100 bytes. I think this should not be a
problem in terms of resource usage. (They are allocated as const buf:
array [0..99] of byte)
About thread save.
The code already was not thread save, because the variable "e" Which
contains the file handle etc, is a normal global variable (Apparently in
order to be able to close it in the units finalisation).
Of course normally that doesn't mean to add to the fault. Yet for now I
have allocated the buffer as global var too.
There are 2 ways to make it thread save:
1) Make e and buf threadvar
It will still only be 100 bytes per thread (probably it would even be
fine with 50 bytes per thread), so the memory usage would still not be
too bad.
2) Protect "GetLineInfo" with a spin lock
That is probably preferable anyway
Otherwise, I have no idea about the coding style used in fpc. So sorry
if my patch does not follow it.
Also I made 2 procedures "inline", I have not tested how much time that
gains, but I guess it is minor. So if that isn't compliant with the code
guidelines, remove it
Martin
Index: rtl/inc/lnfodwrf.pp
===================================================================
--- rtl/inc/lnfodwrf.pp (revision 14167)
+++ rtl/inc/lnfodwrf.pp (working copy)
@@ -53,9 +53,13 @@
type
Bool8 = ByteBool;
+const
+ EBUF_SIZE = 100;
var
{ the input file to read DWARF debug info from, i.e. paramstr(0) }
e : TExeFile;
+ EBuf: Array [0..EBUF_SIZE-1] of Byte;
+ EBufCnt, EBufPos: Integer;
DwarfErr : boolean;
{ the offset and size of the DWARF debug_line section in the file }
DwarfOffset : longint;
@@ -177,6 +181,8 @@
limit := aLimit;
Init := (aBase + limit) <= e.size;
seek(e.f, base);
+ EBufCnt := 0;
+ EBufPos := 0;
index := 0;
end;
@@ -196,39 +202,69 @@
begin
index := newIndex;
system.seek(e.f, base + index);
+ EBufCnt := 0;
+ EBufPos := 0;
end;
{ Returns the next Byte from the input stream, or -1 if there has been
an error }
-function ReadNext() : Longint;
+function ReadNext() : Longint; inline;
var
bytesread : SizeInt;
b : Byte;
begin
ReadNext := -1;
- if (index < limit) then begin
- blockread(e.f, b, 1, bytesread);
- ReadNext := b;
+ if EBufPos >= EBufCnt then begin
+ EBufPos := 0;
+ EBufCnt := EBUF_SIZE;
+ if EBufCnt > limit - index then
+ EBufCnt := limit - index;
+ blockread(e.f, EBuf, EBufCnt, bytesread);
+ EBufCnt := bytesread;
+ end;
+ if EBufPos < EBufCnt then begin
+ ReadNext := EBuf[EBufPos];
+ inc(EBufPos);
inc(index);
- end;
- if (bytesread <> 1) then
+ end
+ else
ReadNext := -1;
end;
{ Reads the next size bytes into dest. Returns true if successful,
false otherwise. Note that dest may be partially overwritten after
returning false. }
-function ReadNext(var dest; size : SizeInt) : Boolean;
+function ReadNext(var dest; size : SizeInt) : Boolean; inline;
var
- bytesread : SizeInt;
+ bytesread, totalread : SizeInt;
+ r: Boolean;
+ d: PByte;
begin
- bytesread := 0;
- if ((index + size) < limit) then begin
- blockread(e.f, dest, size, bytesread);
- inc(index, size);
+ d := @dest;
+ totalread := 0;
+ r := True;
+ while (totalread < size) and r do begin;
+ if EBufPos >= EBufCnt then begin
+ EBufPos := 0;
+ EBufCnt := EBUF_SIZE;
+ if EBufCnt > limit - index then
+ EBufCnt := limit - index;
+ blockread(e.f, EBuf, EBufCnt, bytesread);
+ EBufCnt := bytesread;
+ if bytesread <= 0 then
+ r := False;
+ end;
+ if EBufPos < EBufCnt then begin
+ bytesread := EBufCnt - EBufPos;
+ if bytesread > size then bytesread := size;
+ System.Move(EBuf[EBufPos], d[totalread], bytesread);
+ inc(EBufPos, bytesread);
+ inc(index, bytesread);
+ inc(totalread, bytesread);
+ end;
end;
- ReadNext := (bytesread = size);
+ ReadNext := r;
end;
_______________________________________________
fpc-devel maillist - fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel