-
Content Count
1977 -
Joined
-
Last visited
-
Days Won
26
Everything posted by Attila Kovacs
-
@limelect thx for confirming. It was acquired by emba, It's in getit, so there will be no new releases for older IDE's.
-
How to increase the distance between TCheckBox glyph and caption text?
Attila Kovacs replied to PeterPanettone's topic in VCL
All good. It was in my comment that this is only for static text, and if you would argue then you should have asked what if somebody want 2.5 x space distance 😉 -
How to increase the distance between TCheckBox glyph and caption text?
Attila Kovacs replied to PeterPanettone's topic in VCL
btw. how did you separate the words back in the high school? -
How to increase the distance between TCheckBox glyph and caption text?
Attila Kovacs replied to PeterPanettone's topic in VCL
of course does it work, just set the font size to 2. what is your problem? -
How to increase the distance between TCheckBox glyph and caption text?
Attila Kovacs replied to PeterPanettone's topic in VCL
Only if the text is dynamic or multilang. So in 99.99% the cases could work. Caption = ' Unga'#13#10' Bunga' WordWrap = True -
I installed from the sources, I never install binaries. I don't even have a Delphi like those precompiled versions. I don't even get it why are they different, nevermind.
-
It's indeed promising, but there are several issues. At least with the github version, I'm not sure if it's the latest version though.
-
@Lars Fosdal Hmm, okay, then something strange happening here. As I wrote, ctrl-b (bookmark or what) pressed on the welcome page.
-
Translations of the exception notification dialog text
Attila Kovacs replied to dummzeuch's topic in Delphi IDE and APIs
google: site:.jp delphi debug project1.exe or something like that. however no luck with site:.fr. they must be awesome coder 😉 -
Translations of the exception notification dialog text
Attila Kovacs replied to dummzeuch's topic in Delphi IDE and APIs
This won't help you, am I right? 😉 Maybe this: -
total pointless debate, doesn't matter a thing which one you call, and the implementation won't change in the next 40 years, nor the bug will be fixed.
-
Ok, no "for" loop, no "xor" etc.. which hides implementation details on Char, and reverted back to text=LineBreak delivers 1 empty string for compatibility reasons (original TString / .Split(), etc...) procedure TStringList.SetTextStr(const Value: string); var P, P2, fc, Start, LineBreakEnd: PChar; s: string; LineBreakLen: integer; LLineBreak: PChar; begin BeginUpdate; try Clear; P := Pointer(Value); if P <> nil then begin LLineBreak := PChar(LineBreak); LineBreakLen := Length(LLineBreak); if LineBreakLen > 0 then begin LineBreakEnd := LLineBreak + LineBreakLen; fc := LLineBreak; Start := P; while P^ <> #0 do begin while (P^ <> fc^) and (P^ <> #0) do Inc(P); if P^ <> #0 then begin P2 := P + 1; Inc(fc); while fc^ <> #0 do begin if P2^ <> fc^ then Break; Inc(P2); Inc(fc) end; if fc = LineBreakEnd then begin SetString(s, Start, P - Start); Add(s); P := P2; Start := P; end else Inc(P); fc := LLineBreak; end; end; if P > Start then begin SetString(s, Start, P - Start); Add(s); end; end else Add(Value); end; finally EndUpdate; end; end;
-
@Mahdi Safsafi Can you give me a test case for the incorrect handling of the trailing? This would be important to know. In the meanwhile I made a non-recursive version as Stefan pointed out it should be faster, I knew it, but for some reason I decided to make it with a recursive nested procedure. And as the RTL version was unable to handle the mentioned file, with a faulty LineBreak (#10#10#13), and my version worked like a charm I did not go for any further optimization. And by the way, thus did it became a good example for OoOE. This is the new last one: Stefan means, I could achieve even better results without the "for", but I could not. It's beyond me. I rolled out the first contact to the LineBreak and therefor the "for" is not reached too often. I think I reached the max effort I can put into this (time/pay off). It's also faster than yours by the way, and your implementation fails on 7 test-cases of mine. procedure TStringList.SetTextStr(const Value: string); var P, fc, Start: PChar; b: boolean; i: integer; s: string; LineBreakLen: integer; LLineBreak: string; begin if LineBreak = #13#10 then inherited else begin BeginUpdate; try Clear; P := Pointer(Value); if P <> nil then begin LLineBreak := LineBreak; LineBreakLen := Length(LLineBreak); if LineBreakLen > 0 then begin fc := Pointer(LineBreak); Start := P; while P^ <> #0 do begin while (P^ <> fc^) and (P^ <> #0) do Inc(P); if P^ <> #0 then begin b := True; for i := 1 to LineBreakLen - 1 do if (P + i)^ <> (fc + i)^ then begin b := False; Break; end; if b then begin SetString(s, Start, P - Start); Add(s); Inc(P, LineBreakLen); Start := P; end else Inc(P); end; end; if P > Start then begin SetString(s, Start, P - Start); Add(s); end; end else Add(Value); end; finally EndUpdate; end; end; end;
-
I was struggling to write this down or not, poor dummzeuch's thread is hijacked as hell, but I can't stand, sorry. I cached the property LineBreak as Stefan suggested, but I could not P2 and LineBreakLen. Brain overflow. (less opcode, less stack usage) Then, I inverted the "if" in the middle, because the most likely branch is not to have a LineBreak at the current position in the string. (theoretically OoOE) Then I put Exit()'s instead of "Result :=" which resulted in 2 more exit points, which allows the compiler to use more registers instead of the stack. (less opcode, more register and less stack usage) Finally it went down to around 265ms (from 300), and I got a code which is far from any straightforward thinking and looks ugly and harder to understand. Maybe the last Exit() is unnecessary but this is not the point. It's interesting, how tiny things can affect the speed. Originally I was starting from 320ms and it was a replacement for the RTL which was using 10's of seconds to do the same thing. But I barely think that anybody could/would get used to it to write "if then else begin <actual code> end;" just because the most likely branch would be to do nothing. function IsBreak(AChar: PChar; ALineBreakPos: integer = 1): boolean; begin if AChar^ <> #0 then begin P2 := AChar; if (AChar^ <> LLineBreak[ALineBreakPos]) or (ALineBreakPos > LineBreakLen) then Exit(False) else Exit(IsBreak(AChar + 1, ALineBreakPos + 1)); end else Exit(True); end;
-
@A.M. Hoornweg I have recently "installed" DUnitX back to the IDE by adding its bpl to the packages (install packages) from \Users\All Users\Documents\Embarcadero\Studio\xx.0\Bpl However, not 10.4 and not because of the patch tool
-
Again with memory leaks and FastMM4
Attila Kovacs replied to Alberto Paganini's topic in RTL and Delphi Object Pascal
maybe a non-graceful exit? maybe there were running some indy threads in the background? the leaked string is in the dump, reference count: 1, string: "/api/login" btw. debugging session could also lead to leaked strings. -
@Alexander Sviridenkov Those implicit try/except blocks are really slow, you are right. These OoOE compliant codes are not so spectacular but they could sum up. I took a random example from htutils.pas, "AnsiStartsWith" and changed the early exit against "if (ls > lt) and (lt > 0) then .. else ...", as this is the most likely to happen and this is the path which will be predicted and I can measure around 5.5% faster code with a long "s" and a long "start" parameter. But I really needed long parameters + many many runs to be able to measure anything.
-
As this is a nested proc, the generated code has no multiple exit points. Actually it's a very clean and straightforward asm, so no gain with your changes, rather a tick slower as you assigning the result twice. My original change however was shocking for me, same code, its parts in different order, 6.25% faster.
-
Ok, here is a real-world example. In the code from https://quality.embarcadero.com/browse/RSP-29731 the original nested proc was: function IsBreak(AChar: PChar; ALineBreakPos: integer = 1): boolean; begin P2 := AChar; if AChar^ = #0 then Exit(True); Result := AChar^ = LineBreak[ALineBreakPos]; if Result and (ALineBreakPos < LineBreakLen) then Result := Result and IsBreak(AChar + 1, ALineBreakPos + 1); end; after changing it to: function IsBreak(AChar: PChar; ALineBreakPos: integer = 1): boolean; begin P2 := AChar; if AChar^ <> #0 then begin Result := AChar^ = LineBreak[ALineBreakPos]; if Result and (ALineBreakPos < LineBreakLen) then Result := Result and IsBreak(AChar + 1, ALineBreakPos + 1); end else Result := True; end; the time for reading an 50MB file with 227000 lines went from around 320ms to 300ms down, whereas the 2 codegens are the same except the conditional jump and that the "Exit(true)" is on the bottom (Result:=True). This must be OoOE, isn't it? It's impressive.
-
@Mahdi Safsafi No, this was my question 🙂 "As a general rule, most if not all Intel CPUs assume forward branches are not taken the first time they see them. See Godbolt’s work." After reading the articles again, I would say, "forward branches are not taken the first time" means, no conditional forward jumps are taken by the predictor for the first time. Am I right?
-
@Mahdi Safsafi I see thx. Which one is the forward branch again? The if or the else section? I'm not sure here anymore.
-
@Mahdi Safsafi Thx for your explanation through the example with source code, really nice. I was curious how the prediction works and found that "As a general rule, most if not all Intel CPUs assume forward branches are not taken the first time they see them. See Godbolt’s work." and "Forward branches dominate backward branches by about 4 to 1 (whether conditional or not). About 60% of the forward conditional branches are taken, while approximately 85% of the backward conditional branches are taken (because of the prevalence of program loops). Just knowing this data about average code behavior, we could optimize our architecture for the common cases. A "Static Predictor" can just look at the offset (distance forward or backward from current PC) for conditional branches as soon as the instruction is decoded. Backward branches will be predicted to be taken, since that is the most common case. The accuracy of the static predictor will depend on the type of code being executed, as well as the coding style used by the programmer. These statistics were derived from the SPEC suite of benchmarks, and many PC software workloads will favor slightly different static behavior." However I did not found anything about "first time they see them", in what inertia system are they considered as "first seen". This means, we can tell that at the first "if" in the example above, the prediction is "not to take the else case". Not sure what happens on the next call to the method though,
-
@Kas Ob. Ah, I see, what you were referring to. But this was/should be the case even without knowing any implementation detail of the CPU. At least for me. Yes, considering this, an early exit could screw the cpu's o-of-order algo. Interesting.
-
@Kas Ob. Nice, this quote about Intel and their work. Now, how does an early exit vs. an "if then begin end;" differ, as the Delphi compiler, as far I have seen until now, does not multiply the return code but results in jumps to the end. Only the condition changes, true/false.
-
And how do you measure the out-of-order-execution's algorithm's power consumption? Isn't it possible that for saving some cycles in the code, this algo in the cpu has to consume a bit more energy?