Graphic changes lazarus / 39-Graphics ---------------------------------------------------------------------- lagprogramming · 2014-10-20 22:13 Lazarus version 1.2.6 users that are tired of graphic related bugs and slowdowns have the opportunity to replace some of them with other bugs and other slowdowns.     All you have to do is extract the archive in the Lazarus directory and then rebuild Lazarus. It's easy. A patch for svn revision is added here: http://forum.lazarus.freepascal.org/index.php/topic,26199.msg161684.ht ml#msg161684 ---------------------------------------------------------------------- Mike.Cornflake · 2014-10-21 01:08 Do you have a list of changes?  I note you have some entries in Mantis.   Is this an agregate of those, or is there new fixes in here? ---------------------------------------------------------------------- lagprogramming · 2014-10-21 07:06 Do you want me to attach a file with comments?    After changing the file I think you may have to check many mantis bugs related to graphics. ---------------------------------------------------------------------- Mike.Cornflake · 2014-10-21 08:01 Quote from: lagprogramming on October 21, 2014, 09:06:46 am   Do you want me to attach a file with comments? Not for me thanks, I don't have time to go through your code and compare it with existing...  I think it would be better if you uploaded a series of dedicated patches to Mantis (or even one large patch).  You'd need to be specific on changes as you're asking others to do a LOT of work if you do it that way.  My concern is one of longevity of your work.  As you've done it now, it's valid for entirely as long as the Lazarus Team don't make changes to their own copy of this unit.  (essentially you've forked this unit :-) ).  There may come a day when users of your version are unable to copy the file over the existing without encountering compiler errors. Entirely up to you though.  I'm not doubting you've done good work, and I appreciate the spirit of sharing.  If you're happy maintaining a forked unit, go for it :-) ---------------------------------------------------------------------- lagprogramming · 2014-10-22 17:43 I agree with you, but unfortunately main developers are not satisfied with the way I work. It looks to me like I bother them with my proposals. At the same time, I don't see things the way they do.    It's one of the reasons I try to support the community without their help.    Anyway. I upload an archive for lazarus 1.2.6 users. Many graphic related bugs are affected. The ones that had to work with some bugs(not only mantis reported) have the possibility to try something new, maybe a workaround lies in this archive.    I wish them good luck! ---------------------------------------------------------------------- taazz · 2014-10-23 04:09 Quote from: lagprogramming on October 22, 2014, 07:43:35 pm   I agree with you, but unfortunately main developers are not satisfied with the way I work. It looks to me like I bother them with my proposals. At the same time, I don't see things the way they do. Well so far I have seen nothing that would make me download your files in your messages. Just some generic mention about an alternative way to do things bugs and slow downs that are not mentioned specifically. Of course I will not download or even look at your code if there is nothing in the description that captures my eye I have enough of my own code to write/correct to spend time in something else. So you should edit the first post add as many of the bugs that are corrected as possible with a short description (one or two sentences nothing more) and the link to the bugtracker report of the bug. also what is speed up and how eg if you changed the logic behind the procedure used using a new algorithm then that algorithm should be named or just state not described though. Just something I can read in less than 2minutes and see if I'm interested to look in the code. After that we can talk about what you should do to make your changes available to the main developers in way that they will be interested to spend some time in validating your solution, but as it is now you have no chance on people looking at your code. ---------------------------------------------------------------------- lagprogramming · 2014-10-30 21:38 In order to apply the patch for svn revision 46737 you need to type: svn checkout http://svn.freepascal.org/svn/lazarus/trunk@46737 lazarus Some reports that may be affected: http://bugs.freepascal.org/view.php?id=21589 http://bugs.freepascal.org/view.php?id=24241 http://bugs.freepascal.org/view.php?id=18429 http://bugs.freepascal.org/view.php?id=20205 http://bugs.freepascal.org/view.php?id=20226 http://bugs.freepascal.org/view.php?id=25080 http://bugs.freepascal.org/view.php?id=20205 *** http://bugs.freepascal.org/view.php?id=26093 http://bugs.freepascal.org/view.php?id=25405 ---------------------------------------------------------------------- marcov · 2014-10-31 10:10 Most of those bugs have no patches attached? ---------------------------------------------------------------------- lagprogramming · 2014-11-01 16:21 And some notes that may need further attention: gtk2winapi.inc.function TGtk2WidgetSet.PostMessage within "CombinePaintMessages" something looks wrong when "(NewMsg^.Message=LM_GTKPAINT)and(OldMsg^.Message=LM_GtkPAINT)" because we just copy data into local variables. gtk2winapi.inc.function MessageButtonClicked Looks like it doesn't do what is advertised. Always returns false. customform.inc. function TCustomForm.CloseQuery: boolean; might not return a result.    And by the way, the two archives have been updated. ---------------------------------------------------------------------- JuhaManninen · 2014-11-01 19:23 Quote from: marcov on October 31, 2014, 11:10:41 amMost of those bugs have no patches attached? No, they are all without a patch. Lagprogramming, can you please explain why you don't fix any of those bugs? Instead you blame the developers for treating you bad, which is nonsense. You have provided 5 patches. Most of them were minor cleanup and useless formatting. Still almost all of them were applied, as a sign of good will and to encourage you to also fix bugs. For example this one I applied against Vincent's will :   http://bugs.freepascal.org/view.php?id=26885 Do you now feel insulted because I mentioned that formatting changes are not important and we would need bug fixes instead? Only this one maybe fixed a small bug but I am not sure:   http://bugs.freepascal.org/view.php?id=25693 I did not look at your code now but I don't believe it fixes any bugs. Otherwise you would have mentioned it clearly. ---------------------------------------------------------------------- lagprogramming · 2014-11-02 01:27 @JuhaManninen    “You have provided 5 patches. Most of them were minor cleanup and useless formatting. Still almost all of them were applied, as a sign of good will and to encourage you to also fix bugs. For example this one I applied against Vincent's will :”    This means that you deserve an explanation.    In order to explain you'll need more than two minutes to read, but that's nothing compared to my efforts of writing this.    "Lagprogramming, can you please explain why you don't fix any of those bugs?"    1) We don't share the same interests. You are interested in closing as many bugs possible, I'm interested in code execution speed.    I lost hope in a good lcl many years ago. The antidote I have for the bugs: I use only basic components and even those might be overridden. For example, a TListbox might be completely drawn by my application(100%, even the text characters don't depend on existing fonts installed). At this level I doubt that mantis bugs will affect me much.  So, I don't have a personal interest in closing mantis bugs.    But this means I'm interested in speed, obviously I've found lots of things that can be improved both in Fpc and Lazarus, things that I've considered can be applied without a big effort from main developers. This is the reason why there were PROPOSALS of minor modifications. If these minor changes are not welcome, what about the big ones!? Those were PROPOSALS, nothing more. I don't expect you to agree with them, you just accept them or not, I don't feel offended no matter what decision you take. 2) You have many bugs that apparently share the same source, but the way lcl is designed makes debugging very hard and you know it. This is why I consider it's useful to pinpoint the areas with problems. Even a function result that may not be assigned is important because nobody can say what is the impact on the bugs(filled or not within mantis). But simply pointing such minor problems will make main developers pretend a patch from the reporter or even worse(developers closing tickets not only without solving the problems, but stating that it's not a problem at all). So, not only that I don't have a reason to fix bugs, but now I have no reason to report within mantis my findings. 3) Many bugs hide additional problems, problems that are hard to spot. Look at the comment I've done at the “0021589: TBitmap.SaveToFile does not work with monochrome Bitmaps” report. It's enough to add 10 characters in the source file to close the ticket, but I've noticed additional problems there. Closing the ticket will hide those problems and again many years might take to implement 64bit bitmaps there. People won't know where is the problem. The transparent bitmaps, again, it remains a workaround, because the original function is so ugly I'd rather stare at the sun than at it. Why should I offer a patch to main developers with a workaround for the bug, knowing that the patch will make even harder to debug other bugs(including not yet reported ones). Also, in my work I don't connect my findings with existing bug reports. For example, I remember that there was a function that didn't created a palette for monochrome bitmaps  I think, but without connecting this situation with a ticket, I would have disturbed main developers again. Later I've found another ticket something related to a form save or load, I don't remember now exactly, it was related to monochrome bitmaps. 4) You complain about those minor proposals. If you accept a proposal, I have to keep track of it until next stable release and immediately after for a while. That takes me much more time than you need to analyze the proposal. So, each time I propose something to you, if you accept the change I'd have to work harder than you. For example, between the last stable Lazarus and trunk only about 10 functions/procedures have been modified by both me and main developers. The files presented have more than 200 modifications. Do you realize what would happen if I'd propose all of them to you and you'd accept all of them, each and every one of them with minor variations!? )    “Instead you blame the developers for treating you bad, which is nonsense.”    I don't blame developers for not sharing the same interests or the same points of view. At the same time main developers should accept that I can offer support to the community without their help. However I can't say that I'm very happy with situations like: Proposal report for zero and near zero comparisons where main developer says that it's fixed. “0026794: Slow code generated for for near zero{-1,1} comparisons [feature]” New report without any response. “0026925: "For" loops optimizations proposal [feature]” I tell you what this means. I've written code according to what the main developer said and after a while I've discovered that the code produced was not optimized. I had to modify again the code to manually optimize the zero comparisons. A lot of work for what, and some of you complain about 2 minutes?! Is this reasonable?! What about this report. “0026089: Slow code generated for if...then...else” The support for the workaround came from ordinary developers like me, not from the main ones. That's not a problem, however, the discouraging attitude of the main developers is something unpleasant but probably necessary . Main Lazarus developers do the same, so it's not like I lack experience in this field. Last time I've checked the following function was 15 times faster than original. Code: [Select]function TFPReaderBMP.CountBits(Value : byte) : shortint; var i : shortint; begin result:=0; for i:=0 to 7 do   begin     if (value and byte(1))<>0 then inc(result);     value:=value shr 1;   end; end;    Why should I fill a ticket knowing that my proposals are not welcome?! “Do you now feel insulted because I mentioned that formatting changes are not important and we would need bug fixes instead?”    We have different understandings regarding formatting. By formatting change I understand lines, spaces, comments...modifications that don't influence binary produced code. Formatting change: 1)var x:integer    y:integer; 2)var x,y:integer; Examples when binary code produced differs(meaning that it's not just a formatting change in my point of view): 1)Begin x:=10;if y=0 then exit;z=6;end; 2)Begin if y=0 then exit(10);z=6;end; or 1)if pointer=nil then Result:=0 else Result:=1; 2)if pointer<>nil then Result:=1 else Result:=0;    Personal conclusions:    I think there are few Fpc/Lazarus main developers really active. Looking at the code and at the attitude I have reasons to believe that the number won't greatly increase in the future. I consider Fpc rtl sources structured and optimized much better than Lazarus's lcl. I realize that a new developer might have a shock looking at the lcl. I think the way the code is structured is prone to bugs, reason why you have so many reports, bugs that are harder to pinpoint compared to fpc's rtl ones.    Example regarding code structure: procedure DefaultReaderDescription(AWidth, AHeight: Integer; ADepth: Byte; out ADesc: TrawImageDescription);   The way it's structured, is prone to bugs. There are many routines like this one. This procedure needs total rewrite in my point of view. The files provided by me contain a workaround for one of the reports(static text I think) where this procedure has been modified, but the solution lies in rewriting the procedure so that you won't initialize with default 24bit values and after that modify some of those values as it does now. “I did not look at your code now but I don't believe it fixes any bugs. Otherwise you would have mentioned it clearly.”    Anyway, the modifications are not done for main developers and are not intended to close bugs. These correlations appeared as a side effect. Also, I don't need reviews from main Lazarus developers regarding the code modified by me as I know very well what I've modified and why. I just offer an alternative to those that need a little bit of snappiness from the lcl and some additional informations to main developers that may be interested. FOR MAIN DEVELOPERS THE PASCAL CODE IS USELESS, IT'S THE FINDINGS THAT MAY MATTER, like those in P.S.. If I do it in mantis you disagree because I occupy your time, if I do it on the forum you also disagree. It's not like I earn something from any of you, and also you are free to take whatever you find useful from my modifications. I don't care if any of you uses anything at all from these files, meaning that I also don't care much about texts like: “After that we can talk about what you should do to make your changes available to the main developers in way that they will be interested to spend some time in validating your solution, but as it is now you have no chance on people looking at your code.” P.S. I wrote this text off-line so I don't know if I mentioned these before: procedure TBitmap.LoadFromStream(AStream: TStream; ASize: Cardinal); It might not work when “{$IFDEF ENDIAN_BIG}”. Swap might require to be treated as a function not a procedure. function TWinControl.SendDialogChar(var Message : TLMKey): Boolean; Original function didn't always returned result. Could it be related to a bug, something like: when I open  the program if I keep shift pressed the key is not detected, or something like that?! function TGtk2WidgetSet.GetClipBox(DC : hDC; lpRect : PRect) : Longint; What happens if "lpRect=nil and IsValidDC(DC)??? TGtk2WidgetSet.GetRgnBox checks for nil better than this function. function TGtk2WidgetSet.GetClipRGN(DC: hDC; RGN: hRGN): Longint; A bug may be introduced here. It is advertised that the function has to return values {-1,0,1} but default value is 2(SIMPLEREGION). ---------------------------------------------------------------------- User137 · 2014-11-02 07:48 About formatting, this one seems off. Let me mark indent begins and ends Quotefunction TFPReaderBMP.CountBits(Value : byte) : shortint; var i : shortint; begin result:=0; for i:=0 to 7 do   begin     if (value and byte(1))<>0 then inc(result);     value:=value shr 1;   end; end;That's as far as eye sees it, but clearly if i thought it this way, i wouldn't be able to distinct that the last end; belongs to procedure. Why can't we all just have this: Code: [Select]function TFPReaderBMP.CountBits(Value : byte) : shortint; var i : shortint; begin   result:=0;   for i:=0 to 7 do   begin     if (value and byte(1))<>0 then inc(result);     value:=value shr 1;   end; end;Alternatively putting "begin" right after "do" would still keep the indents right. There should be indent after begin always, even when it belongs to function or procedure word. Much easier to read code. ---------------------------------------------------------------------- JuhaManninen · 2014-11-02 12:25 Yes, LCL code has its issues. Lots of glue code is needed sometimes and the code is messy. However it is not improved by micro-optimization as you are doing now. For example in the issue #26885 you eliminated temporary values stored in a variable. The compiler can already do such micro-optimization, you don't need to worry about it. As Vincent mentioned the original code was better for debugging, but I applied it mostly to make you happy. For some reason you are still not happy ... In some patch you found an uninitialized variable. That was a bug, please keep reporting those findings. Thanks. I looked at your FPC if..then..else issue. Comments from the FPC developers seemed reasonable. You again concentrate in wrong things. If you really can speed up some relevant code *15 times, please report it with a patch and a test program. I believe it will be accepted. Somehow I am suspicious about your speedups though. About the difference between Lazarus release and trunk, you should always use trunk when testing bugs and creating patches. I can recommend trunk, it works well. ---------------------------------------------------------------------- BrunoK · 2014-11-02 14:22 1 - Source code style   When patching source code (even for my own "trunk"), I always try to respect the original style.   When too unreadable, I try to JEDI format the code, it doesn't work always, but when it works it gives a good idea of what happens in the code, then put my modifications back to the original file keeping its original format style. 1b - Source code style   Re : Vincent Snijders in #26885, agree.   I much prefer the original code because it is easier to put DEBUGGER stop points when the code is unwound line wise in source. 2 - CountBits.   TFPReaderBMP.CountBits looks a bit strange due to its use of the mod operator my own version would be  : Code: [Select]function TFPReaderBMP.CountBits(Value: byte): shortint; begin   Result := 0;   while Value <> 0 do begin     if (Value and 1) <> 0 then       Inc(Result);     Value := Value shr 1;   end; end;   my tests give some improvement (test it) speed-wise. As for Inc(Result); being put on another line, in this case it doesn't make much difference, but in more complicated bits of code, it may be very helpful for debugging. 3 - TWinControl.SendDialogChar   If I remember well, lagprogramming is probably right on the point of result not being correctly cleared.   In my personal trunk the code is Code: [Select]function TWinControl.SendDialogChar(var Message : TLMKey): Boolean; var   ParentForm: TCustomForm; begin   ParentForm := GetParentForm(Self);   Result:=assigned(ParentForm);   if Result then begin     Result := ParentForm.DialogChar(Message);     if Result then       Message.CharCode := VK_UNKNOWN;   end; end;   Why not compact the conditions ? because when debugging and single stepping it helps to have steps on different lines. (see 1b above). And it is a place in the code where I spent quite a lot of time. ;-) 4 - http://bugs.freepascal.org/view.php?id=25405   Effectively, Delphi handles it a bit differently.   The point would be to have a simple demo program showing what problem is caused by the item position in the Controls [] list. In Delphi it was possible to change the non visual create order and that did actually solve some problems with Master/Detail table opening at form/datamodule's creation. ---------------------------------------------------------------------- lagprogramming · 2014-11-02 15:12 @BrunoK Regarding source code style each time I analyze, I completely rearrange it. Takes a lot of time because the difference in formatting is huge. After I modify the code, I don't know how to rearrange it backwards. I know how I format my code, I don't understand how original code is formated, mainly because I disagree with some things that I've seen. So, it has to be a very simple function/procedure to modify it and keep the formatting, otherwise there is absolutely no hope in providing any welcome and readable patch. Regarding 0026885 I understand the point of view of main developers. But it's just a proposal, it's not like I've considered the modification absolutely necessary. They can say: “The change may lead to improvements but debugging that line might become a bottleneck, or the formatting style is not common amongst us, reason why readability is greatly reduced.”. I got: “How does your personal code formatting affect patch creation? You changed LCL source and copied it here after all. If you plan to contribute for Lazarus in future, you must learn to create patches.” Regarding 4 - http://bugs.freepascal.org/view.php?id=25405 It's one of the reasons why I advertise that bugs may be replaced new ones. It's partially applied but I also wondered about how the tabs should be inserted. @JuhaManninen    I can keep track of source file changes easy enough. If other users need a little bit of snappiness, they can try the modified files provided by me freely. It's not a guarantee they will find a solution inside but it's hope. I can easily update the patches, you've seen that already. So, I don't benefit much from current activity of the main developers much. Users that might be interested in using the modified sources are those that have serious problems regarding flickering(frames) and so one. So, regarding Lazarus, few users might benefit from this work, while main developers can't do much for those users. So, when I propose something to you, I consider it might be useful to you. It's just that almost each time main developers backfire the proposals to me. It's not a reason to be upset. It's just that I've tried many times to present you some situations and many times the developers looked bothered by that.    What's important for me might not be important for somebody else, I accept that. This is the reason why, in order to keep everybody happy and to give back something good to the community I stopped filling reports and started using the forum. This way, users may benefit(partially from the changes because I don't present all of them) and main developers might be interested in some findings that I present. But even this approach appears to bother main developers.    If you want me to post what I consider abnormal in a different way, you can say so, but  I don't feel like polluting the mailing lists would be better. Maybe you may be interested in what I find within the sources, but others don't.    Regarding. “Comments from the FPC developers seemed reasonable.”. I understand their point of view but I can't say that I'm happy with the way the main developers “encourage” people. I'm one of those that stopped filling bug reports and I'm sure I'm not the only one. Let's face it, each report filled bothers, reason why each main developer refers to mantis tickets in previous comments of this post. Contrary to main developers, Do-wan Kim provided a patch that(as average) provides 10% speed increase on CPUs in that situation. If the main developers would have closed the ticked we wouldn't have the workaround now. It's a situation where me and the main developers disagreed with benefits for everybody. The same thing might happen here. I understand some of your point of views reason why I stopped presenting my proposals within mantis. But I present them here, I don't keep them hidden.    So even if we have different opinions, the pascal community is already fragmented enough. Take what's good from my work, if you consider there is any within it, and move on. If you want me to present what I find curious within the sources in a different approach, clearly PROPOSE so, I don't feel bothered. It's just that, regarding my work, I don't know what exactly are main developers interested in, neither the way they prefer to receive the feedback. Maybe you'd consider a new “Lazarus>proposals” entry within Mantis, or a new subject within the forums, I really don't know. ---------------------------------------------------------------------- JuhaManninen · 2014-11-02 15:37 Lagprogramming, to summarize your posts: You have lots of talk but little substance behind it. I also must agree with User137, your formatting style is extremely weird. ---------------------------------------------------------------------- BrunoK · 2014-11-02 20:06 Or maybe even : Code: [Select]function TFPReaderBMP.CountBits(Value: byte): shortint; begin   Result := 0;   while Value <> 0 do begin     Result:=Result+(Value and 1);     Value := Value shr 1;   end; end; ---------------------------------------------------------------------- BrunoK · 2014-11-02 20:11 which could be extended to Code: [Select]function TFPReaderBMP.CountBits(Value: ): shortint; begin   Result := 0;   while Value <> 0 do begin     Result:=Result+(Value and 1);     Value := Value shr 1;   end; end; ---------------------------------------------------------------------- lagprogramming · 2014-11-03 13:48 In order to apply the patch for svn revision 47287 you need to type: svn checkout http://svn.freepascal.org/svn/lazarus/trunk@47287 lazarus Then patch the sources using the file attached to this message. ---------------------------------------------------------------------- lagprogramming · 2014-11-03 13:52 Apparently some developers already use the modifications, in important projects ignoring that I've clearly stated from the very beginning that some existing bugs might be replaced with new ones. This makes me feel like I have to remove some modifications and tell what that was about, so that those of you that use previous modifications, will be prepared for what's worse. a) procedure DefaultReaderDescription REMAINS    The workaround consisted in adding: “25..32 : Adesc.Init_BPP32_B8G8R8A8_BIO_TTB(AWidth,Aheight);” to the case statement. 32bit descriptions were not filled correctly. This is one of the reasons for some transparency bugs. The problem with this workaround is that we initialize using alpha(32 bit Depth) while original code and most of the lcl appears to be prepared for 24bit Depth. There is a subtle difference between bits per pixel and depth, but there is and I have reasons to think that some lcl sources didn't make the difference between these two either. 32 bits per pixel images can be treated like 24 ones if we chose to ignore the alpha byte. So this modification may surface things that I really can't predict. I know that old versions of Windows had problems with 32bit Depth bitmaps. So, I don't consider this modification safe enough. Also, I don't know how compatible is with "pf32bit:Flags := [riqfRGB, riqfMask, riqfAlpha];" found in TCustomBitmap.RawimageNeeded. For now, this one remains but might have unpleasant side effects. b) procedure TlazIntfImage.SetMasked REMOVED    Fortunately this one was disabled. Some notes on this one. "and ((self.Width and 3) = 0)" has been added. Probably related to multiple bugs like: 0024241,0025080..... Extras: Width has to be multiple of 4 to use masks.  This might be another bug in Fpc/Lazarus, a widget optimization requirement similar to padding of 24bit bitmaps or something else.  It is required both width and height to be multiple of 4 but apparently it works just with width.  http://coronalabs.com/blog/2012/05/29/how-to-use-bitmap-masks/}  //((self.Width and 3) = 0) is the optimized version of ((self.Width mod 4) = 0)    I didn't had enough informations, reason why I've disabled the modification by using comments. It might be related to transparency problems. c)procedure TwinControl.PaintControls REMAINS Both original and modified codes consider that during paint(during the while/for loop)FControls must be steady(no switches, insertions, removals). Is this OK??? d)procedure TwinControl.Insert REMOVED Has been modified to really insert, not append. One of the reasons for modifying it was that I knew that lcl has problems with z-ordering. I verified that maybe the reason was connected to the fact that you couldn't set the right position in a list. You try to insert in a specific position and you end up in a different position. The problem with this modification is that apparently, it breaks compatibility with Delphi and also I don't know the following thing: if “Acontrol.CanTab=false”should the control be inserted in the FtabList? I've decided to remove this modification, although even now I consider the modification a better solution than the original. e) procedure TcustomBitmap.Changed REMOVED    I knew that modifying the bitmap is not tracked by parent controls. For example, apparently changing the pixelformat is entirely ignored. For this reason I've inserted: “if FPixelFormatNeedsUpdate then UpdatePixelFormat;”    The line has been inserted because procedures like "Assign" or "RawimageNeeded" set "FPixelFormatNeedsUpdate:=TRUE;" without calling anything else after that    The problem is that I'm not sure this is the wright place to do. procedure TcustomBitmap.SetPixelFormat REMOVED If the pixel format is changed then call Changed(Self); If the changed event should not be triggered then "Changed(Self);" may be replaced by "UpdatePixelFormat". I've removed both modifications. ---------------------------------------------------------------------- lagprogramming · 2014-11-06 12:13 Changes: 1) When csdesigning, execution should be slower, otherwise it should be a little bit faster. 2) This is the first time I publicly present tracked inlines within the sources. The following text will present what's with this kind of changes. Untracked inlines are manual function inlines only the developer knows about, modifications that ignore the code outside the block. For example: original code Code: [Select]var p:point; p:=point(0,0); modified code Code: [Select]var p:point; p.X:=0;p.Y:=0; This modification is not tracked, meaning that It's assumed that the "point" function will never change. Now I'll start talking about tracked inlines by using an example. Within lclmessageglue.pas and lmessages.pp we find: Code: [Select]function LCLSendPaintMsg(const Target: TControl;const  DC: HDC; const PaintStruct: PPaintStruct): PtrInt; var   Mess: TLMPaint; begin   FillChar(Mess, SizeOf(Mess), 0);   Mess.Msg := LM_PAINT;   Mess.DC := DC;   Mess.PaintStruct := PaintStruct;     Result := DeliverMessage(Target, Mess); end; and Code: [Select]  TLMPaint = record     Msg: Cardinal; {$ifdef cpu64}     UnusedMsg: Cardinal; {$endif}     DC: HDC;     PaintStruct: PPaintStruct;     Result: LRESULT;   end;    The use of "fillchar" brings at least three benefits a)It's a safe way to initialize memory blocks. b)Makes the code easily maintainable and readable. c)May reduce code size.    The downside effect is that it reduces code execution speed. As can be seen, the memory block filled with zeros immediately gets written again, without using the zeros. Modified source follows: Code: [Select]function LCLSendPaintMsg(const Target: TControl;const  DC: HDC; const PaintStruct: PPaintStruct): PtrInt; var Mess:TLMPaint; begin Mess.Msg:=LM_PAINT; {$ifdef cpu64}Mess.UnusedMsg:=0;{$endif} Mess.DC:=DC; Mess.PaintStruct:=PaintStruct; Mess.Result:=0; Result:=DeliverMessage(Target,Mess); end;    Using untracked inlines in this situation, makes the code prone to bugs if the structure of TLMPaint changes.    This is why a succesful modification of the function "LCLSendPaintMsg" depends on the structure of the "TLMPaint" record. Obviously, there may be a chain of dependencies, for example the order of the entities found in the "uses" statement, but I think I've briefly presented this feature enough .    Regarding code execution speed, I think it has the potential to increase the image of FPC/Lazarus built applications by adding a plus of snappiness(or lower power consumption). I wonder how many compilers/IDEs offer a similar package to the community.    I'd like to point out that the svn patch doesn't contain all modifications. Functions/procedures modified by main developers since the stable release are not included in the patch(14 modifications at the moment).    The latest svn patch is at: http://forum.lazarus.freepascal.org/index.php/topic,26199.msg161684.ht ml#msg161684 ---------------------------------------------------------------------- lagprogramming · 2014-11-11 10:59 Ticket "0026284: PNG with special resolution not show in runtime" is also affected by the modifications.    I'd like to know if anybody noticed any kind of regression using the modified files compared to original ones. ---------------------------------------------------------------------- Laksen · 2014-11-11 13:52 I wonder what the talk about CountBits is? This version is 20 times faster on my system. Code: [Select]function TFPReaderBMP.CountBits(Value: byte): shortint; begin   Result := PopCnt(Value); end; ---------------------------------------------------------------------- ChrisF · 2014-11-11 15:11 It seems that the PopCount function is only available in the trunk version of FPC. I guess it's probably using directly the intrinsic popcount assembly instruction when available for the targeted processor. Otherwise, looking briefly at the source code, it's using a 4 bits lookup table (at least for the FPC 2.6.x branch) when not available, which seems quite effective for a byte value too. Just for information purposes, counting the number of bits, also known as the Hamming weight, can also been done through the well-known "Swar algorithm": Sample code for a 32 bits value (can be easily extended): Code: [Select]function Swar(Value: Longword): shortint; begin   Value := Value - ((Value shr 1) and $55555555);   Value := (Value and $33333333) + ((Value shr 2) and $33333333);   result := (((Value + (Value shr 4)) and $0F0F0F0F) * $01010101) shr 24; end; ---------------------------------------------------------------------- lagprogramming · 2014-11-11 16:20 @Laksen I think you've had the most elegant approach. It fits great within the function. @ChrisF's I also think that your approach might be better than what's currently implemented within fpc for non-byte parameters(probably byte can be optimized too). Briefly looking, current implementation, appears like: Code: [Select]variable:=0; repeat variable:=variable+1; {CODE}; until variable=7; Assembler for popcnt Code: [Select]fpc_popcnt_dword 0000000000444AA0 90                       nop 0000000000444AA1 b800000000               mov    $0x0,%eax 0000000000444AA6 48be0000000000000000     movabs $0x0,%rsi 0000000000444AB0 4883ee01                 sub    $0x1,%rsi 0000000000444AB4 66666690                 data32 data32 xchg %ax,%ax 0000000000444AB8 4883c601                 add    $0x1,%rsi 0000000000444ABC 89fa                     mov    %edi,%edx 0000000000444ABE 83e20f                   and    $0xf,%edx 0000000000444AC1 488d0dd8da5500           lea    0x55dad8(%rip),%rcx      # 0x9a25a0 0000000000444AC8 0fb61411                 movzbl (%rcx,%rdx,1),%edx 0000000000444ACC 01d0                     add    %edx,%eax 0000000000444ACE 89fa                     mov    %edi,%edx 0000000000444AD0 c1ea04                   shr    $0x4,%edx 0000000000444AD3 89d7                     mov    %edx,%edi 0000000000444AD5 4883fe07                 cmp    $0x7,%rsi 0000000000444AD9 7cdd                     jl     0x444ab8 0000000000444ADB 90                       nop 0000000000444ADC c3                       retq  0000000000444ADD 0000                     add    %al,(%rax) 0000000000444ADF 00                       add    %dl,0x41(%rbx) Assembler for Code: [Select]function Swar(Value: Longword): longword; begin   Value := Value - ((Value shr 1) and $55555555);   Value := (Value and $33333333) + ((Value shr 2) and $33333333);   result := (((Value + (Value shr 4)) and $0F0F0F0F) * $01010101) shr 24; end; Code: [Select] .type UNIT1_$$_SWAR$LONGWORD$$LONGWORD,@function UNIT1_$$_SWAR$LONGWORD$$LONGWORD: .Lc1: .Ll1: # [unit1.pas] # [39] begin nop # Var Value located in register eax # Var $result located in register eax .Ll2: # [40] Value := Value - ((Value shr 1) and $55555555); movl %edi,%eax shrl $1,%eax andl $1431655765,%eax subl %eax,%edi # Var Value located in register edi .Ll3: # [41] Value := (Value and $33333333) + ((Value shr 2) and $33333333); movl %edi,%eax shrl $2,%eax andl $858993459,%eax andl $858993459,%edi leal (%eax,%edi),%eax # Var Value located in register eax .Ll4: # [42] result := (((Value + (Value shr 4)) and $0F0F0F0F) * $01010101) shr 24; movl %eax,%edx shrl $4,%edx andl $4294967295,%edx andl $4294967295,%eax leaq (%rdx,%rax),%rax andq $252645135,%rax imulq $16843009,%rax,%rax shrq $24,%rax # Var $result located in register eax .Ll5: # [43] end; nop ret    The situation might worsen with qword. Apparently popcnt(qword) calls popcnt(dword) two times. ---------------------------------------------------------------------- BrunoK · 2014-11-11 20:36 ChrisF is the winner. Good timings for worst condition. Beats all for more general cases . Where did you find this algorithm ? ---------------------------------------------------------------------- ChrisF · 2014-11-11 21:25 Quote from: BrunoK on November 11, 2014, 09:36:58 pmWhere did you find this algorithm ? The official name is the "variable-precision SWAR algorithm". Some infos about SWAR: - http://en.wikipedia.org/wiki/SWAR - http://www.aggregate.org/SWAR/ and more precisely about this particular algorithm: - http://www.aggregate.org/MAGIC/#Population%20Count%20%28Ones%20Count %29 And a few more about its implementation and some explanations: - http://stackoverflow.com/questions/109023/how-to-count-the-number- of-set-bits-in-a-32-bit-integer - http://stackoverflow.com/questions/22081738/how-variable-precision- swar-algorithm-works - http://www.playingwithpointers.com/swar.html All the credit goes to the concerned authors... Anyway, I guess that the popcnt assembly instruction(s) (at least for Intel and AMD processors) are probably faster. ---------------------------------------------------------------------- lagprogramming · 2014-11-16 12:46 Minor changes. pixmap.inc LazResourceXPMToPPChar contains "XPMSource:=LazarusResources.Find(ResourceName);". XPMSource may be nil and the following line doesn't check for that. Modified code checks for nil. gtk2widgetset.inc TGtk2WidgetSet.LoadPixbufFromLazResource calls for LazResourceXPMToPPChar within an "try...except...end;" block but after that it tries to continue as if no error has been raised in the meantime. ---------------------------------------------------------------------- lagprogramming · 2014-11-16 18:52 LPTODP & DPtoLP    These are two very often used functions. The functions return a "BOOL" result. "BOOL" is the equivalent of LongBool while "Boolean" is the equivalent of ByteBool. Obviosly, by using different sizes lots of useless assembler instructions appear, increasing size, decreasing speed. I see that this design is spread all over the lcl. Is this situation a consequence of copy/pasting code from one place to another, or there is an unknown(to me) reason behind this design. I really can't find a reason to use "BOOL" instead of "Boolean" for those functions. ---------------------------------------------------------------------- taazz · 2014-11-16 21:43 Quote from: lagprogramming on November 16, 2014, 07:52:46 pmLPTODP & DPtoLP    These are two very often used functions. The functions return a "BOOL" result. "BOOL" is the equivalent of LongBool while "Boolean" is the equivalent of ByteBool. Obviosly, by using different sizes lots of useless assembler instructions appear, increasing size, decreasing speed. I see that this design is spread all over the lcl. Is this situation a consequence of copy/pasting code from one place to another, or there is an unknown(to me) reason behind this design. I really can't find a reason to use "BOOL" instead of "Boolean" for those functions. http://msdn.microsoft.com/en- us/library/windows/desktop/dd145042%28v=vs.85%29.aspx ---------------------------------------------------------------------- lagprogramming · 2014-11-17 10:03 @taaz Yes but, function TGtk2WidgetSet.LineTo(DC: HDC; X, Y: Integer): Boolean; http://msdn.microsoft.com/en- us/library/windows/desktop/dd145029%28v=vs.85%29.aspx or function TGtk2WidgetSet.MoveToEx(DC: HDC; X, Y: Integer; OldPoint: PPoint): Boolean; http://msdn.microsoft.com/en- us/library/windows/desktop/dd145069%28v=vs.85%29.aspx Appears to be the same situation. We have "bool" changed to "boolean". If it has been done for LineTo or MovetoEx, why don't we do the same with LPtoDP and DptoLP? That size change difference might slow down things that are already slow. Fortunately the function result isn't used much within lcl, so we can't talk about a drastic speed decrease to to this reason. ---------------------------------------------------------------------- taazz · 2014-11-17 10:33 Quote from: lagprogramming on November 17, 2014, 11:03:15 am@taaz Yes but, function TGtk2WidgetSet.LineTo(DC: HDC; X, Y: Integer): Boolean; http://msdn.microsoft.com/en- us/library/windows/desktop/dd145029%28v=vs.85%29.aspx or function TGtk2WidgetSet.MoveToEx(DC: HDC; X, Y: Integer; OldPoint: PPoint): Boolean; http://msdn.microsoft.com/en- us/library/windows/desktop/dd145069%28v=vs.85%29.aspx Appears to be the same situation. We have "bool" changed to "boolean". If it has been done for LineTo or MovetoEx, why don't we do the same with LPtoDP and DptoLP? That size change difference might slow down things that are already slow. Fortunately the function result isn't used much within lcl, so we can't talk about a drastic speed decrease to to this reason. Get over the size change, it is not your bottleneck even by defining the result as boolean the size change will happen since the prototype is already in bool it has to be converted to boolean to be assigned as the result of the function any way. In short the change will always happen if you assign it to a boolean variable if you use it directly you might overcome the change problem but I haven't test that either. I doubt that you will get any meaningful speed enhancement though. ---------------------------------------------------------------------- lagprogramming · 2014-11-18 14:21 1) For gtk2, I've manually inlined the "LPtoDP" and "DPtoLP" functions where they were called(LineTo, Rectangle are the most important ones I think). By doing so I've removed some useless CPU instructions, especially when the last parameter of the functions was "1".    2) Now, there is an additional thing I'd like to test: the influence of the "DebugLn" statements. I've seen many of them are not conditionally compiled("{$ifdef.....}"). Even when "DebugLn" is not used, there may be a "jmp" instruction to pass over the code. Also, by building a file without "DebugLn" I expect a smaller memory footprint, which might have a surprising effect on CPU cache, thing that may improve code execution speed. Also, I forgot now where, but I've seen local variables declared only to be used together with "DebugLn", variables that are not conditionally compiled either. If the presence of these "DebugLn" drag down code execution speed, I'd like to know if "DEBUG" define symbol should be used in order to conditionaly compile them. I'd like to use a single symbol because "DebugLn" is found in many files and I don't want to change the code all over again a second time. If this change will affect binary file stripping, do you know how it will do it? ---------------------------------------------------------------------- taazz · 2014-11-18 19:46 Quote from: lagprogramming on November 18, 2014, 03:21:49 pm   1) For gtk2, I've manually inlined the "LPtoDP" and "DPtoLP" functions where they were called(LineTo, Rectangle are the most important ones I think). By doing so I've removed some useless CPU instructions, especially when the last parameter of the functions was "1". Let me know what is the speed gain on those places is it worth the rtouble or its something along the lines of 0.0001 seconds every 10 million executions. Quote from: lagprogramming on November 18, 2014, 03:21:49 pm   2) Now, there is an additional thing I'd like to test: the influence of the "DebugLn" statements. I've seen many of them are not conditionally compiled("{$ifdef.....}"). Even when "DebugLn" is not used, there may be a "jmp" instruction to pass over the code. Also, by building a file without "DebugLn" I expect a smaller memory footprint, which might have a surprising effect on CPU cache, thing that may improve code execution speed. Also, I forgot now where, but I've seen local variables declared only to be used together with "DebugLn", variables that are not conditionally compiled either. If the presence of these "DebugLn" drag down code execution speed, I'd like to know if "DEBUG" define symbol should be used in order to conditionaly compile them. I'd like to use a single symbol because "DebugLn" is found in many files and I don't want to change the code all over again a second time. If this change will affect binary file stripping, do you know how it will do it? There was an enhancement a few years back that allowed the debugln to be used as needed and replaced with empty functions when it was not needed. I was under the impression that the compiler would remove all empty functions from the final compiled code and eliminate the calls to it if not its something that should be considered for inclusion in the future. Or it was eliminating only the empty inlined function this way? Sorry can't remember exactly. In general I'm against adding debugging functionality this way but the lack of a good debugger in lazarus it makes this a must have, In my opinion debug code should be deleted from any released code before shared to the public, as for the debug define no it should not use it it should use a debug specific for the feature debugged (dbg_KeyboardEvents) or in case that is generic then a define that will be used only by the project in question eg LAZ_DEBUG to avoid enabling it by mistake. ---------------------------------------------------------------------- howardpc · 2014-11-18 22:48 Quote from: taazz on November 18, 2014, 08:46:47 pmThere was an enhancement a few years back that allowed the debugln to be used as needed and replaced with empty functions when it was not needed. I was under the impression that the compiler would remove all empty functions from the final compiled code and eliminate the calls to it if not its something that should be considered for inclusion in the future. Or it was eliminating only the empty inlined function this way? Sorry can't remember exactly. Yes, if you replace "uses lazlogger;" with "uses lazloggerdummy;" all DebugLn() calls are replaced by empty procedures (I presume it is done  something along the lines of the way Assert() can be removed). Under what optimization specifics or other conditions (if indeed there are any) the compiler might then eliminate empty DebugLn routines  I do not know. ---------------------------------------------------------------------- lagprogramming · 2014-11-18 23:06 Using recently updated fpc trunk with level 3 optimizations: 1) Pascal written procedure follows: Code: [Select]procedure z; var localvariable:integer; begin for localvariable:=0 to 100 do; end; assembler code produced follows: Code: [Select].section .text.n_unit1_$$_z .balign 16,0x90 .globl UNIT1_$$_Z .type UNIT1_$$_Z,@function UNIT1_$$_Z: .Lc1: .Ll1: # [unit1.pas] # [34] begin nop # Var localvariable located in register eax # Var localvariable located in register eax .Ll2: # [35] for localvariable:=0 to 100 do; movl $0,%eax subl $1,%eax .balign 8,0x90 .Lj7: addl $1,%eax cmpl $100,%eax jl .Lj7 .Ll3: # [36] end; nop ret .Lc2: .Lt1: .Le0: .size UNIT1_$$_Z, .Le0 - UNIT1_$$_Z    Empty loops are not removed, which might lead to the possibility, in certain circumstances, that CPU registers allocation is unpleasantly affected. 2) What follows was a surprise to me. The idea of this part was to show that even if we have an empty procedure, as long as we pass function results as parameters to this empty procedure, we still have assembler code produced. Example, "DebugLn(floattostr(sin(x)))" would always compute "floattostr(sin(x))" because apparently, the compiler doesn't know if a function result is used or not. In my point of view even if the function result is not used the function should be executed(except for "if...short circuit...then" situations). I thought that empty procedures/routines don't produce code and are not called. Looking at assembler code appears I was wrong, at least when functions are passed as parameters. Pascal code follows: Code: [Select]function simplefunction:string; begin result:='SimpleFunctionResult'; end; procedure emptyprocedure(parameter:string); begin // end; procedure procedurecall; begin emptyprocedure(simplefunction); end; Assembler code follows: Code: [Select].section .text.n_unit1_$$_simplefunction$$ansistring .balign 16,0x90 .globl UNIT1_$$_SIMPLEFUNCTION$$ANSISTRING .type UNIT1_$$_SIMPLEFUNCTION$$ANSISTRING,@function UNIT1_$$_SIMPLEFUNCTION$$ANSISTRING: .Lc3: .Ll5: # [40] begin nop leaq -8(%rsp),%rsp .Lc5: # Var $result located in register rax # PeepHole Optimization,MovMov2Mov1 movq %rdi,%rax .Ll6: # [41] result:='SimpleFunctionResult'; movq $_$UNIT1$_Ld1,%rsi call fpc_ansistr_assign .Ll7: # [42] end; leaq 8(%rsp),%rsp nop ret .Lc4: .Lt2: .Le1: .size UNIT1_$$_SIMPLEFUNCTION$$ANSISTRING, .Le1 - UNIT1_$$_SIMPLEFUNCTION$$ANSISTRING .Ll8: .section .text.n_unit1_$$_emptyprocedure$ansistring .balign 16,0x90 .globl UNIT1_$$_EMPTYPROCEDURE$ANSISTRING .type UNIT1_$$_EMPTYPROCEDURE$ANSISTRING,@function UNIT1_$$_EMPTYPROCEDURE$ANSISTRING: .Lc6: .Ll9: # [45] begin nop leaq -8(%rsp),%rsp .Lc8: # Var parameter located at rsp+0, size=OS_64 # PeepHole Optimization,MovMov2Mov1 movq %rdi,(%rsp) call fpc_ansistr_incr_ref .Ll10: # [47] end; movq %rsp,%rdi call fpc_ansistr_decr_ref leaq 8(%rsp),%rsp nop ret .Lc7: .Lt3: .Le2: .size UNIT1_$$_EMPTYPROCEDURE$ANSISTRING, .Le2 - UNIT1_$$_EMPTYPROCEDURE$ANSISTRING .Ll11: .section .text.n_unit1_$$_procedurecall .balign 16,0x90 .globl UNIT1_$$_PROCEDURECALL .type UNIT1_$$_PROCEDURECALL,@function UNIT1_$$_PROCEDURECALL: .Lc9: # Temps allocated between rsp+0 and rsp+104 .Ll12: # [50] begin nop leaq -104(%rsp),%rsp .Lc11: .Ll13: movq $0,96(%rsp) movq %rsp,%rdx leaq 24(%rsp),%rsi movl $1,%edi call FPC_PUSHEXCEPTADDR movq %rax,%rdi call FPC_SETJMP movq %rax,88(%rsp) testl %eax,%eax jne .Lj18 .Ll14: # [51] emptyprocedure(simplefunction); leaq 96(%rsp),%rax movq %rax,%rdi call UNIT1_$$_SIMPLEFUNCTION$$ANSISTRING movq 96(%rsp),%rdi call UNIT1_$$_EMPTYPROCEDURE$ANSISTRING .Lj18: .Ll15: call FPC_POPADDRSTACK .Ll16: # [52] end; leaq 96(%rsp),%rdi call fpc_ansistr_decr_ref .Ll17: movq 88(%rsp),%rax testq %rax,%rax je .Lj19 call FPC_RERAISE .Lj19: .Ll18: leaq 104(%rsp),%rsp nop ret .Lc10: .Lt4: .Le3: .size UNIT1_$$_PROCEDURECALL, .Le3 - UNIT1_$$_PROCEDURECALL 3) Adding up previous two paragraphs we end up with: {CODE THAT WHEN I NEED IT I CAN'T FIND IT, ALTHOUGH I'VE SEEN THE SITUATION MORE THAN ONCE}    It was something like: Code: [Select]begin of loop with counter variable declared to be used only for this loop if condition then debugln('text'+function_call_result+'text.'); end of loop ---------------------------------------------------------------------- lagprogramming · 2014-12-01 21:44 This is the first time I publicly present included optional CPU branch removal. 1/4 Foreword for pascal programmers that don't know what CPU branches are about    Many processors are able to compute more than one line of code at a time. This means that two(or more) lines of pascal code can be computed in parallel(almost at the same time), improving code execution speed. However, once we hit an "if", "case" or loop("repeat", "for"...) the situation becomes complex. The CPU is not 100% sure what's best to be done, it may stall(wait) or try to guess. Apparently it is better to try guessing than waiting . When the processor fails to predict if the code found at "then" or "else"(branches) block is the appropriate one, usually it fails with a sensible decrease of code execution speed(localy). Depending on the combination of CPU model and fpc version(as there is hope), the decrease can be small or huge.    Anyway, at the moment, branch misses are bottlenecks for new CPU models, no matter the language or compiler used. Older CPU models might not have appropriate optimizations within fpc, so they might hit the speed penalty too. All of these CPU share this bottleneck: the presence of conditional jumps("if", "case"...statements). 2/4 Drawbacks of branch removal    Previous uploaded modified code(files) already had some branch removals.    I'M NOT SURE THE FOLLOWING EXAMPLE IS THE BEST ONE!!!    For example:    "If (sourcewidth=0)and(sourceheight=0)and(destinationwidth=0)and(de stinationheight=0) then copyimageoptimized;".    Can be changed to something like:    "If (sourcewidth or sourceheight)=0)and(destinationwidth or destinationheight=0) then copyimageoptimized;"//TWO BRANCHES    or    "If (sourcewidth or sourceheight or destinationwidth or destinationheight)=0 then copyimageoptimized;"//ONE BRANCH    or    "{$B+} If (sourcewidth=0)and(sourceheight=0)and(destinationwidth=0) and(destinationheight=0) then copyimageoptimized; {$B-}"//ONE BRANCH    The problem with the above alternatives is that those "or" instructions are not for free. Those are operations that take time.    This means that the situation is like the following text(JUST AS EXAMPLE):    Original code(with branches):    "if {condition} then {dothen} else {doelse};"    will take 10  millisecond if the CPU guesses the condition;    will take 20 milliseconds if the CPU misses the condition;    Modified code(without branches):    will take 13  milliseconds all the time(there is no "if" statement).    Between original and modified codes, if you consider the branch- less code(with time consumed for additional operations like the "or" in the above example) will statistically perform better, you may activate the option. Regarding code execution speed there is no universal safe solution...and there won't be. 3/4 Who might benefit from branch removal.    New CPU models might benefit because they are fast for many things except for branch misses recovery.    Some old CPU models that predict poorly and fpc might not have proper optimizations for them. For example, at the moment, I expect AMD K8(probably K10 too) series to run Lazarus/Fpc built binaries slow. For these CPUs, apparently, regarding branches("then" or "else" code blocks), even if the CPU predicts corectly the branch, some code might need to be aligned(something that fpc might not do properly at the moment ). This means that the simple existence of an "if", "case" or any loop within the pascal code can become a bottleneck, no matter branch prediction influence. Also, apparently a series of more than three consecutive conditional jumps is highly susceptible to mess the branch predictor.    Regarding software, I've never used Code Typhoon but probably this "branch"(distribution) has the potential to benefit more than "vanilla" Lazarus because of it's easier cross-compiling target. 4/4 How to enable branch removal    Use "-dBRANCHREMOVAL"(without quotes).    TEXT PRESENTED ABOVE IS JUST AN INTRODUCTION! IF YOU'RE LOOKING FOR MORE INFORMATIONS(OR MORE ACCURATE) REGARDING CPU BRANCHES TRY NOT TO USE THIS FORUM THREAD. ---------------------------------------------------------------------- JuhaManninen · 2014-12-02 06:49 Quote from: lagprogramming on December 01, 2014, 10:44:45 pm   TEXT PRESENTED ABOVE IS JUST AN INTRODUCTION! IF YOU'RE LOOKING FOR MORE INFORMATIONS(OR MORE ACCURATE) REGARDING CPU BRANCHES TRY NOT TO USE THIS FORUM THREAD. Huh! Your writings have less and less connection with reality. Please use a personal blog somewhere else instead of polluting the Lazarus forum.