Recent

Author Topic: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)  (Read 5652 times)

RAW

  • Hero Member
  • *****
  • Posts: 868
For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« on: September 03, 2017, 10:25:42 am »
If I use this FormCreate: FOR loop with 1.000 or 2.000 or 3.000 then everything is fine, but if I use 5.000 or 10.000 or more I get an error (SIGFPE).
??? Why ??? Is this correct ??? Floating Point Error ???

I just wanted to know if I can scroll like this with a lot more text lines than usual...
Is that too long for a String ??? Amiga Division ??? Length ???
Code: Pascal  [Select][+][-]
  1. Procedure TForm1.FormCreate(Sender: TObject);
  2.   Var
  3.    str: String;
  4.    i  : Integer;
  5.  Begin
  6.   DoubleBuffered:= True;
  7.   KeyPreview    := True;
  8.  
  9.   For i:= 1 To 1000
  10.   Do str:= str+'THE LAST OF THE MOHICANS - HELLO WORLD'+IntToStr(i)+sLineBreak;
  11.  
  12.   Label1.Caption:= str+'END of TEXT';
  13.   Label1.SetBounds(0, 0, ClientWidth, ClientHeight);
  14.  
  15.   iFontHeight:= Label1.Canvas.TextHeight('HITMqQiyYöÖ');
  16.  End;
  17.  
  18.  
  19. Procedure TForm1.ScrollUp(cSpeed: Cardinal);
  20.   Var
  21.    c: Cardinal;
  22.  Begin
  23.   For c:= 0 To cSpeed
  24.   Do
  25.    Begin
  26.     If Label1.Top >= 0 Then Exit;
  27.     Label1.Top:= Label1.Top + iFontHeight;
  28.    End;
  29.  End;
  30.  
  31.  
  32. Procedure TForm1.ScrollDown(cSpeed: Cardinal);
  33.   Var
  34.    c: Cardinal;
  35.  Begin
  36.   For c:= 0 To cSpeed
  37.   Do
  38.    Begin
  39.     If Label1.Top <= ClientHeight - Label1.Height Then Exit;
  40.     Label1.Top:= Label1.Top - iFontHeight;
  41.    End;
  42.  End;

The Debugger points me here: Line 8.
Code: Pascal  [Select][+][-]
  1. procedure RaiseGDBException(const Msg: string);
  2. begin
  3.   debugln(rsERRORInLCL, Msg);
  4.   // creates an exception, that gdb catches:
  5.   debugln(rsCreatingGdbCatchableError);
  6.   DumpStack;
  7.   {$ifndef HASAMIGA} // On Amiga Division by 0 is not catchable, just crash
  8.   if (length(Msg) div (length(Msg) div 10000))=0 then ;
  9.   {$endif}
  10. end;
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #1 on: September 03, 2017, 10:52:15 am »
this is a debugger trap as far as I can see nothing to do with your code. Have you tried it outside the debugger? does it still raises the error? If I had to guess I would say that the error is handled internally or it is an external exception that has nothing to do with your code from a dll perhaps? Keep in mind that in windows there was an upper limit on scrolling ( 15bits 32K or so) the last time I checked.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #2 on: September 03, 2017, 11:03:02 am »
Setting a breakpoint in the RaiseGDBException routine and looking at the stacktrace leads me to this:

Code: Pascal  [Select][+][-]
  1. procedure TControl.DoSetBounds(ALeft, ATop, AWidth, AHeight : integer);
  2.  
  3.   procedure BoundsOutOfBounds;
  4.   begin
  5.     DebugLn('TControl.DoSetBounds ',Name,':',ClassName,
  6.       ' Old=',dbgs(Left,Top,Width,Height),
  7.       ' New=',dbgs(aLeft,aTop,aWidth,aHeight),
  8.       '');
  9.     RaiseGDBException('TControl.DoSetBounds '+Name+':'+ClassName+' Invalid bounds');
  10.   end;
  11.  
  12. begin
  13.   if (AWidth>100000) or (AHeight>100000) then
  14.     BoundsOutOfBounds;
  15. ...

i.e., your label is too large because its AutoSize is on by default. Turn off AutoSize, and the program works.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #3 on: September 03, 2017, 10:36:58 pm »
Quote
Have you tried it outside the debugger?
Yes.. I've got always a Division by zero kind of error...

Quote
Keep in mind that in windows there was an upper limit on scrolling ( 15bits 32K or so) the last time I checked.
Interesting.. never thought about this...

Quote
i.e., your label is too large because its AutoSize is on by default. Turn off AutoSize, and the program works.
Yes, the error is gone if I set AutoSize to FALSE.. but then this way of scrolling will not work anymore.. btw. not a big problem I just wanted to know when then scrolling speed in going down or when it's too slow...

Quote
begin
  if (AWidth>100000) or (AHeight>100000) then
    BoundsOutOfBounds;
Yes, my size would be 165033 (Height), so it's a SetBounds problem... very strange, what is the exact reason for programming such a OutOfBounds thing??? Anyway not a big deal, I normally use this for 100 to 1.500 lines and that's very fast and working very nice AND looks much better than a Listbox or ScrollBox, so I'm happy that I can use this on a form or inside a panel... (Classic Theme btw.) If I set it to 3.000 lines then it's a bit slower, but it's still fast enough to work with it...  :)

Quote
Setting a breakpoint in the RaiseGDBException routine ...
Yeah, that's something I really need to do... I've never really used the debugger in a good way... should learn this asap...

Thanks @wp and @taazz...
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #4 on: September 04, 2017, 12:44:07 am »
Why don't you use a Memo?

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #5 on: September 04, 2017, 01:13:11 am »
so it's a SetBounds problem... very strange, what is the exact reason for programming such a OutOfBounds thing???

I don't know. I looked at the svn commit notes and found that it was introduced in r5202, Feb 17 2004; the commit message was "fixed TCustomImage.DoAutoSize fixing uninitialized vars". Maybe the reason to introduce this limitation is no longer valid? I'd propose that you edit your control.inc (make a backup copy), remove this limitation and test your program with even larger labels. See what happens. If nothing happens write a bug report and propose to remove the limitation (although I am rather sure that your application is not a good test case for the issue that was solved with it). Maybe somebody takes care of the issue... (But be prepared to be asked why you don't use the scrolling capabilities of a memo  ;) )
« Last Edit: September 04, 2017, 01:15:25 am by wp »

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #6 on: September 04, 2017, 05:20:19 am »
Quote
Why don't you use a Memo?
Yes, that's a good idea a memo scrolls a lot better (Classic Theme) than a Listbox or Scrollbox or ListView... at least the last time I've tested this...
A memo is a little bit more work... get rid of the caret and the context menu .. and so on.. but that's no big deal. I guess it's similar to Delphi then I can use old code. (WndProc and Focus stuff...)

Quote
I'd propose that you edit your control.inc (make a backup copy), remove this limitation and test your program with even larger labels.
That's the very nice thing with open source, I thought about that and keep that in mind. Right now I don't need more than 1.000 lines, so it's not directly necessary for me.

Quote
(But be prepared to be asked why you don't use the scrolling capabilities of a memo  ;) )
Yeah...  :)
I've never really tested how much lines a memo can handle without any lack of speed...

I always wanted to do a component that can handle a big amount of text and looks good with a classic theme, but I never got the time to play around with that.
On the other hand there are a lot ready to use components out there that I don't have tested so far. For example VirtualTreeView with really a lot lines of text...
For a lot of programmers this VirtualTreeView is one of the most important components at all...  :)

I've tried to use a TLabel for every line just for fun to see how much I can use, but that' s not working... 100 TLabels are ok, but If I use slightly more then it's totally slow and from time to time I can see flickering (despite DoubleBuffered:= True;)... maybe that was wrong, but I only changed the code slightly to use an array (static and dyn.). The RAM usage is also clearly higher... not a good idea...
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #7 on: September 04, 2017, 10:35:09 am »
I agree that a TMemo may have a lot of overhead due to its editing capabilities.

It's not difficult to write a dedicated "TScrollLabel" - see code below. I don't see a reason why it should slow down with the count of lines, and in fact I can increase the upper limit of the i loop in FormCreate up to 1000000 without seeing any limitation in scrolling (there is some initial dely, of course, due to creation of the 1 million lines).

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.   TScrollLabel = class(TGraphicControl)
  12.   private
  13.     FLines: TStrings;
  14.     FTopLine: Integer;
  15.     FLineHeight: Integer;
  16.     function GetCaption: String;
  17.     function GetFont: TFont;
  18.     procedure SetCaption(const AValue: String);
  19.     procedure SetFont(const AValue: TFont);
  20.     procedure SetLines(const AValue: TStrings);
  21.   public
  22.     constructor Create(AOwner: TComponent); override;
  23.     destructor Destroy; override;
  24.     procedure Paint; override;
  25.     function PageLines: Integer;
  26.     procedure ScrollBy(ADelta: Integer);
  27.     procedure ScrollTo(ALine: Integer);
  28.   published
  29.     property Caption: String read GetCaption write SetCaption;
  30.     property Color;
  31.     property Lines: TStrings read FLines write Setlines;
  32.     property Font: TFont read GetFont write SetFont;
  33.   end;
  34.  
  35. type
  36.  
  37.   { TForm1 }
  38.  
  39.   TForm1 = class(TForm)
  40.     procedure FormCreate(Sender: TObject);
  41.     procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  42.   private
  43.     FScrollLabel: TScrollLabel;
  44.  
  45.   public
  46.  
  47.   end;
  48.  
  49. var
  50.   Form1: TForm1;
  51.  
  52. implementation
  53.  
  54. {$R *.lfm}
  55.  
  56. uses
  57.   LCLType;
  58.  
  59. constructor TScrollLabel.Create(AOwner: TComponent);
  60. begin
  61.   inherited;
  62.   FLines := TStringList.Create;
  63. end;
  64.  
  65. destructor TScrollLabel.Destroy;
  66. begin
  67.   FLines.Free;
  68.   inherited;
  69. end;
  70.  
  71. function TScrollLabel.GetCaption: String;
  72. begin
  73.   Result := FLines.Text;
  74. end;
  75.  
  76. function TScrollLabel.GetFont: TFont;
  77. begin
  78.   Result := inherited Font;
  79. end;
  80.  
  81. function TScrolLLabel.PageLines: Integer;
  82. begin
  83.   Result := Height div FLineHeight;
  84. end;
  85.  
  86. procedure TScrollLabel.Paint;
  87. var
  88.   y: Integer;
  89.   i: Integer;
  90. begin
  91.   Canvas.Font.Assign(Font);
  92.   if FLineHeight = 0 then
  93.     FLineHeight := Canvas.TextHeight('Tg');
  94.   Canvas.Brush.Color := Color;
  95.   Canvas.Brush.Style := bsSolid;
  96.   Canvas.FillRect(0, 0, Width, Height);
  97.  
  98.   y := 0;
  99.   i := FTopLine;
  100.   while (y < Height) and (i < FLines.Count) do begin
  101.     Canvas.TextOut(0, y, FLines[i]);
  102.     inc(y, FLineHeight);
  103.     inc(i);
  104.   end;
  105. end;
  106.  
  107. procedure TScrollLabel.ScrollBy(ADelta: Integer);
  108. begin
  109.   ScrollTo(FTopLine + ADelta);
  110. end;
  111.  
  112. procedure TScrollLabel.ScrollTo(ALine: Integer);
  113. var
  114.   n: Integer;
  115. begin
  116.   if ALine < 0 then
  117.     ALine := 0
  118.   else begin
  119.     n := PageLines;
  120.     if ALine + n >= FLines.Count then
  121.       ALine := FLines.Count - n;
  122.   end;
  123.   FTopLine := ALine;
  124.   Invalidate;
  125. end;
  126.  
  127. procedure TScrollLabel.SetCaption(const AValue: String);
  128. begin
  129.   FLines.Text := AValue;
  130.   FTopLine := 0;
  131.   Invalidate;
  132. end;
  133.  
  134. procedure TScrolLLabel.SetFont(const AValue: TFont);
  135. begin
  136.   inherited Font := AValue;
  137.   Canvas.Font := AValue;
  138.   FLineHeight := Canvas.TextHeight('Tg');
  139. end;
  140.  
  141. procedure TScrollLabel.SetLines(const AValue: TStrings);
  142. begin
  143.   FLines.Assign(AValue);
  144.   FTopLine := 0;
  145.   Invalidate;
  146. end;
  147.  
  148.  
  149. { TForm1 }
  150.  
  151. procedure TForm1.FormCreate(Sender: TObject);
  152. var
  153.   str: String;
  154.   i: Integer;
  155. begin
  156.   FScrollLabel := TScrollLabel.Create(self);
  157.   FScrollLabel.Parent := Self;
  158.   FScrollLabel.Align := alClient;
  159.  
  160. //  DoubleBuffered:= True;
  161.   KeyPreview    := True;
  162.  
  163.   str := '';
  164.   for i:= 1 To 15000 do
  165.     str := str+'THE LAST OF THE MOHICANS - HELLO WORLD'+IntToStr(i)+sLineBreak;
  166.  
  167.   FScrollLabel.Caption := str + 'END of TEXT';
  168. end;
  169.  
  170. procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  171. begin
  172.   case Key of
  173.     VK_UP    : FScrollLabel.ScrollBy(-1);
  174.     VK_DOWN  : FScrollLabel.ScrollBy(+1);
  175.     VK_PRIOR : FScrollLabel.ScrolLBy(-FScrollLabel.PageLines);
  176.     VK_NEXT  : FScrollLabel.ScrollBy(+FScrollLabel.PageLines);
  177.     VK_HOME  : FScrollLabel.ScrollTo(0);
  178.     VK_END   : FScrollLabel.ScrollTo(FScrollLabel.Lines.Count);
  179.   end;
  180. end;
  181.  
  182. end.
« Last Edit: September 04, 2017, 10:37:52 am by wp »

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #8 on: September 04, 2017, 11:51:08 am »
Quote
It's not difficult to write a dedicated "TScrollLabel" - see code below. I don't see a reason why it should slow down with the count of lines, and in fact I can increase the upper limit of the i loop in FormCreate up to 1000000 without seeing any limitation in scrolling (there is some initial dely, of course, due to creation of the 1 million lines).
I cannot see any difference between 2.000.000 and 1.000 lines and no flickering at all... wow, that's indeed very helpful, I can see now that my way to scroll a TLabel is very bad compared to this... and yes I tried a TMemo and really it looks the same... (DoubleBuffered On). Your version is a bit better when it comes to RAM usage, not much 200k... (don't know if I can trust the taskmanager, it's just the only difference that is recognizable...  :)   // yeah.. a memo can do a lot more...  :D

This code could be easily used as basis for a playlist or something like that...
Thank you very much... this is really nice...
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #9 on: September 04, 2017, 10:23:23 pm »
I really like wp's TScrollLabel - straightforward ideas elegantly coded.
Its performance is quite impressive.

I decided to add a few optimisations, and a separate thread for building the super-long string the TScrollLabel is asked to display.
On my machine the scrolling from 0 to the last line for a million-line label is almost instantaneous.

Even with 40 million lines it is hardly slower (though it takes a long time to build the string). 40 million lines gives an overall string length of nearly 2,000 million, close to maxint and the limit of an ansistring's length.
The project I used is attached.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #10 on: September 04, 2017, 11:05:06 pm »
Quote
On my machine the scrolling from 0 to the last line for a million-line label is almost instantaneous.
On my system I cannot see any delay at all...  (10.000.000)  :)
Really nice ...

Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #11 on: September 04, 2017, 11:53:48 pm »
Let's continue the race: Of course, building the super-long string can be accelerated as well. Writing the strings to a memory stream will give a significant boost when the string has reached a certain length. I get:
  • 500.000 lines: appending strings -->1.6 sec, memory stream --> 0.4 sec
  • 1 million lines: appending strings --> 6.0 sec, memory stream --> 0.8 sec
  • 2 million lines: appending strings --> 23.5 sec, memory stream --> 1.6 sec
Appending strings slows down with the square of the line count, in case of the memory stream only linearly.
I added this code to the event handler of two buttons in my example above, one for the "appending strings" method, one for the "stream" method.  (I did not use howardpc's nice thread example because I know what happens when I want to do a quick experiment with threads...)
Code: Pascal  [Select][+][-]
  1. procedure TForm1.BuildString(Sender: TObject);
  2. var
  3.   str: String;
  4.   i: Integer;
  5.   ms: TMemoryStream;
  6.   t: TDateTime;
  7. begin
  8.   t := Now();
  9.   if Sender = Button1 then begin  // Build super-long string by appending strings
  10.     str := '';
  11.     for i:= 1 To NUM_LINES do
  12.       str := str+'THE LAST OF THE MOHICANS - HELLO WORLD'+IntToStr(i)+sLineBreak;
  13.     FScrollLabel.Caption := str + 'END of TEXT';
  14.   end else
  15.   if Sender = Button2 then   // Build string by writing lines to a memory stream
  16.   begin
  17.     ms := TMemoryStream.Create;
  18.     try
  19.       for i:=1 to NUM_LINES do begin
  20.         str := 'THE LAST OF THE MOHICANS - HELLO WORDLD'+IntToStr(i)+sLineBreak;
  21.         ms.Write(str[1], Length(str));
  22.       end;
  23.       str := 'END of TEXT';
  24.       ms.Write(str[1], Length(str));
  25.       ms.Position := 0;
  26.       FScrolllabel.LoadFromStream(ms);
  27.       {
  28.       SetLength(str, ms.Size);
  29.       ms.Position := 0;
  30.       ms.Read(str[1], Length(str));
  31.       }
  32.     finally
  33.       ms.Free;
  34.     end;
  35.   end;
  36.  
  37.   t := Now() - t;
  38.   Label1.Caption := FormatDateTime('s.zzz" sec"', t);
  39. end;
Using a stream-interface for the ScrollLabel, the memory stream can write directly into the label which reduces memory load at the end.
Code: Pascal  [Select][+][-]
  1. procedure TScrollLabel.LoadFromStream(AStream: TStream);
  2. begin
  3.   FLines.LoadfromStream(AStream);
  4.   Invalidate;
  5. end;



Ondrej Pokorny

  • Full Member
  • ***
  • Posts: 220
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #12 on: September 05, 2017, 12:13:48 am »
1.) Why not to feed directly the Lines property (+ implement BeginUpdate/EndUpdate)? Then you don't need any intermediate step with building the text or using TMemoryStream.
2.) Caption is available since TControl. You should not overload/reimplement it but override RealGetText and RealSetText.

wp

  • Hero Member
  • *****
  • Posts: 11858
Re: For loop Error SIGFPE (1.8RC4 FPC 3.0.4)
« Reply #13 on: September 05, 2017, 09:47:40 am »
1.) Why not to feed directly the Lines property (+ implement BeginUpdate/EndUpdate)? Then you don't need any intermediate step with building the text or using TMemoryStream.
Of course...

2.) Caption is available since TControl. You should not overload/reimplement it but override RealGetText and RealSetText.
This is in howardpc's adaption.

 

TinyPortal © 2005-2018