Jump to content

Stefan Glienke

Members
  • Content Count

    1430
  • Joined

  • Last visited

  • Days Won

    142

Everything posted by Stefan Glienke

  1. Stefan Glienke

    Help with string extraction function

    By the way: LoopStuff.dpr.26: while i < count do 0041BDB0 3BFB cmp edi,ebx 0041BDB2 7E0C jle $0041bdc0 LoopStuff.dpr.28: dosomething(i); 0041BDB4 8BC3 mov eax,ebx 0041BDB6 E8D5FFFFFF call dosomething LoopStuff.dpr.29: inc(i); 0041BDBB 43 inc ebx LoopStuff.dpr.26: while i < count do 0041BDBC 3BFB cmp edi,ebx 0041BDBE 7FF4 jnle $0041bdb4 LoopStuff.dpr.26: if (i < count) then // this branch can be emited if i holds at compile time. 0041BDB0 3BFB cmp edi,ebx 0041BDB2 7E0C jle $0041bdc0 LoopStuff.dpr.29: dosomething(i); 0041BDB4 8BC3 mov eax,ebx 0041BDB6 E8D5FFFFFF call dosomething LoopStuff.dpr.30: inc(i); 0041BDBB 43 inc ebx LoopStuff.dpr.31: until (i = count); 0041BDBC 3BFB cmp edi,ebx 0041BDBE 75F4 jnz $0041bdb4 As I said: sometimes the compiler does the check at the top for the while loop.
  2. Stefan Glienke

    Help with string extraction function

    @Mahdi Safsafi I would not use that code as evidence because there actually the for loop produces better code than the other one. I was talking about while x do loop vs if x then repeat until not x conversion. Also it makes a difference if you have a static count or not - the benefit of the for to loop is that the compiler does no additional cmp after it decrements the internal "counting down to zero" variable but does the conditional jmp depending on the outcome of the dec. An until loop produces an additional cmp instruction (reported as https://quality.embarcadero.com/browse/RSP-22124) As always: it depends - while I certainly would not use a for-to loop when dealing with some string parsing but rather prever PChar I just found recently that using a for-to loop with indexing into a pointer was faster than inc(thatpointer).
  3. Stefan Glienke

    Anybody up for an ethics question?

    Giving an error is *always* better than assuming an "instead of" value for invalid data. You can potentially ruin the entire system by doing that. The strategy of giving the error is up to the developer - the "it simply crashes and refuses to do anything with the entire data" is fine. It depends on the data itself if let's say all valid entries can be imported and only the invalid ones can be left out and possibly reported back so the customer can fix them and then import those.
  4. Stefan Glienke

    Assign a pointer to a dynamic array

    Best solution would probably to change the type of segment_ptr but then probably the E2010 pops up somewhere else. Anyhow a simple hardcast will do what it did before they tightened the assignment rule in 10.2: p := TWordArray(segment_ptr); Also shouldn't FastReports have fixed that code some while ago given they support 10.2 and higher?
  5. Backup/restore of a remote git repository is simply backup/restore of a file system folder
  6. I just had a glimpse over the source but I think the line can just be removed. There is nothing to deallocate and any managed fields in the record will be finalized automatically from the RTL.
  7. Stefan Glienke

    GExperts supports even more laziness

    I was not sure what "current" means in the context of being called from the IDE from the hooked "break because of exception" method - but you could be right - that would make it easier.
  8. Stefan Glienke

    Buggy Optimizer in Delphi 10.4

    https://xkcd.com/292/ just saying
  9. Stefan Glienke

    GExperts supports even more laziness

    You probably have to use an IOTADebuggerNotifier to detect ProcessCreated/ProcessDestroyed - there you have to add/remove IOTAProcessNotifier and get ThreadCreated/ThreadDestroyed and you can already guess it add/remove an IOTAThreadNotifier which has ThreadNotify where you are interested in TOTANotifyReason.nrException. The corresponding IOTAThread instance has all the required information like the OSThreadID or Handle properties
  10. Stefan Glienke

    Patch 2 for RAD Studio 10.4 now available

    Just remove the : record constraint from FromRecord and it will work. Just don't pass anything but a record then :p
  11. Stefan Glienke

    Patch 2 for RAD Studio 10.4 now available

    Spring4D is not negatively affected by Patch2
  12. Stefan Glienke

    GExperts supports even more laziness

    Probably possible using the debugger evaluation or something but being able to have an "any" option in the exception class field would be enough - and probably a button "ignore any" in the exception dialog. Currently I am solving this by setting a non breaking breakpoint at the start of the unit tests with "ignore subsequent exceptions" but I forget to set that up often enough.
  13. Stefan Glienke

    GExperts supports even more laziness

    The filters work on Exception class name and that does not support regex or does a sub type check
  14. Stefan Glienke

    GExperts supports even more laziness

    I am really missing a "don't bother me at all about any exception during the current debug session" button.
  15. Stefan Glienke

    Patch 2 for RAD Studio 10.4 now available

    I reported the regression and added a suggestion how to fix this kinda properly (without going too deep into the rabbit hole of extending constraints): https://quality.embarcadero.com/browse/RSP-30078
  16. Stefan Glienke

    Patch 2 for RAD Studio 10.4 now available

    @Vincent Parrett Ewww looks like they made record constraint only allow record with no managed fields although things were just working
  17. Stefan Glienke

    Help with string extraction function

    Just to make sure you don't misunderstand: The common way of compilers (check it for yourself using compiler explorer) to write while x do is to turn it into if x then repeat until not x (simply said). The code you posted could get rid of the check at the bottom because there was nothing else to do after the check for '0' which results in a result true so that basically serves as this loop breaking check. The first check makes sure the loop is even entered at all, otherwise it jumps over it (0 iterations) - the "real" loop condition is at the bottom of the loop body. What is usually not good is to only put the loop condition at the bottom and statically jump over the loop body (because the duplicated condition at the top is missing). Thats two unnecessary jumps for the common case of "at least 1 iteration".
  18. Stefan Glienke

    Help with string extraction function

    Here it is clearly not - but I was referring to the fact that mostly it is the way to do - see this exhaustive answer. But what you typically don't do is to statically jump over the loop body to the condition at the bottom to then conditionally jump back up because the loop very likely runs at least once. Either the compiler restructures the loop or simply puts the loop condition as if ontop of the loop as well (sometimes dcc even does it)
  19. Stefan Glienke

    Help with string extraction function

    At least regarding life expectancy 😉
  20. Stefan Glienke

    Help with string extraction function

    I stopped reading after that because we are in a Delphi forum... Well - I did not - lets see - gcc and clang both generate this (so does vc++ I guess): test1(char const*): .L14: movzx edx, BYTE PTR [eax] test dl, dl je .L15 add eax, 1 cmp dl, 48 jne .L14 mov eax, 1 ret .L15: xor eax, eax ret and this is what Delphi makes out of this function: function Test(str: PAnsiChar): Boolean; var i: Integer; begin i := 0; while str[i] <> #0 do begin if '0' = str[i] then Exit(True); Inc(i); end; Result := False; end; Project25.dpr.13: i := 0; 0041BD90 33D2 xor edx,edx 0041BD92 EB09 jmp $0041bd9d Project25.dpr.16: if '0' = str[i] then Exit(True); 0041BD94 80F930 cmp cl,$30 0041BD97 7503 jnz $0041bd9c 0041BD99 B001 mov al,$01 0041BD9B C3 ret Project25.dpr.17: Inc(i); 0041BD9C 42 inc edx Project25.dpr.14: while str[i] <> #0 do 0041BD9D 0FB60C10 movzx ecx,[eax+edx] 0041BDA1 84C9 test cl,cl 0041BDA3 75EF jnz $0041bd94 Project25.dpr.19: Result := False; 0041BDA5 33C0 xor eax,eax Project25.dpr.20: end; 0041BDA7 C3 ret And the other one: function Test2(str: PAnsiChar): Boolean; var p: PAnsiChar; begin p := @str[0]; while p^ <> #0 do begin if '0' = p^ then Exit(True); Inc(p); end; Result := False; end; Project25.dpr.26: p := @str[0]; 0041BD90 EB09 jmp $0041bd9b Project25.dpr.29: if '0' = p^ then Exit(True); 0041BD92 80FA30 cmp dl,$30 0041BD95 7503 jnz $0041bd9a 0041BD97 B001 mov al,$01 0041BD99 C3 ret Project25.dpr.30: Inc(p); 0041BD9A 40 inc eax Project25.dpr.27: while p^ <> #0 do 0041BD9B 0FB610 movzx edx,[eax] 0041BD9E 84D2 test dl,dl 0041BDA0 75F0 jnz $0041bd92 Project25.dpr.32: Result := False; 0041BDA2 33C0 xor eax,eax Project25.dpr.33: end; 0041BDA4 C3 ret What we can see is that the Delphi compiler is clearly not clever but rather sticks to some hardcoded behavior such as that it is addicted to put loop conditions after the body (which usually is a good pattern) even if it makes little sense to do so. Another thing has to do with the post increment operator that we don't have in Delphi which causes the instruction after the check inside the loop which causes the additional jump because it cannot just restart the loop after it did not find the '0'. Things like that require writing loops in a very ass backwards way in Delphi to get the same code generated. In order to get the same code that the C++ compilers emit you have to write unreadable shit like this: function Test3(str: PAnsiChar): Boolean; var c: AnsiChar; begin repeat c := str^; if c = #0 then Break; Inc(str); if c = '0' then Exit(True); until False; Result := False; end; When I used the local variable p here that I assigned str to it did not even keep using eax but insisted in putting a useless mov into a new register.
  21. Stefan Glienke

    Help with string extraction function

    No, because if you are doing something with whatever is at x[ i ] its faster to use a pointer that starts at @x[ 0 ] and just inc that rather than having a loop which then has 2 counter variables (they like to count down to zero while maintaining the upwards counting i). And on x86 that is a precious register that can be used for something else.
  22. Stefan Glienke

    Help with string extraction function

    Congrats, you just broke it for empty S. Also not storing Pointer(Result) makes it slower at least for me. You have to know where it's worth to put effort and where it does not matter.
  23. Stefan Glienke

    Help with string extraction function

    Yes but who cares for the nop (well for this one at least, yes the Win64 compiler inserts a ton of them in weird places), the next line is the SetLength before the ret.
  24. Stefan Glienke

    Help with string extraction function

    I was merely commenting on the things that can happen when using common practice for benchmarking and comparing different algorithms or implementation by simply putting them all into the same executable and then running them after each other in any order and less so on which of them are affecting this particular test. FWIW here is an optimized version of your routine (tested on 10.3.3 with $O+,W-): - no unnecessary Inc(r)/Dec(r) when '{' was found - no unnecessary check on the inner loop before first Inc(p) - better code generated for inner loop condition - yours generated imul - could even use until (p^ in ['}', #0]) which is even faster but generates W1050 but produces valid code as it uses the 16bit registers still. function ExtractContent(const S: string): string; var p, ep, r, sr: pchar; len: Integer; begin len := S.Length; SetLength(Result, len); r := Pointer(Result); sr := r; p := Pointer(S); ep := p + len; while p < ep do begin r^ := p^; if p^ = '{' then begin repeat Inc(p); until (p^ = '}') or (p^ = #0); end else Inc(r); Inc(p); end; SetLength(Result, r - sr); end;
  25. Stefan Glienke

    Help with string extraction function

    @Kas Ob. Your benchmark is flawed - every time you test multiple implementations in the same test you have a bias because of sorts of things such as memory layout/alignment, branch prediction, prefetcher and so on. For example when I run the code you posted "Kas not fixed wins" - when I comment out all others the code runs slower. When I comment out one of the tests all routines suddenly run faster. This clearly is an indicator that depending on where the code is put by the compiler sometimes they might be sitting in the cache more beneficial than some other times. Unfortunately at least to my knowledge with the Delphi compiler you have no control over code alignment - unless you write stuff in asm if course...
×