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

Reply via email to