-
Content Count
1430 -
Joined
-
Last visited
-
Days Won
142
Everything posted by Stefan Glienke
-
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
@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). -
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.
-
Assign a pointer to a dynamic array
Stefan Glienke replied to dummzeuch's topic in RTL and Delphi Object Pascal
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? -
Why should I use good source control versioning system?
Stefan Glienke replied to Mike Torrettinni's topic in Tips / Blogs / Tutorials / Videos
Backup/restore of a remote git repository is simply backup/restore of a file system folder -
Installing EmbeddedWb package in Delphi 10.4
Stefan Glienke replied to Incus J's topic in RTL and Delphi Object Pascal
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. -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
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. -
https://xkcd.com/292/ just saying
- 7 replies
-
- optimization
- bug
-
(and 1 more)
Tagged with:
-
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
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 -
Patch 2 for RAD Studio 10.4 now available
Stefan Glienke replied to Marco Cantu's topic in General Help
Just remove the : record constraint from FromRecord and it will work. Just don't pass anything but a record then :p -
Patch 2 for RAD Studio 10.4 now available
Stefan Glienke replied to Marco Cantu's topic in General Help
Spring4D is not negatively affected by Patch2 -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
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. -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
The filters work on Exception class name and that does not support regex or does a sub type check -
GExperts supports even more laziness
Stefan Glienke replied to dummzeuch's topic in Tips / Blogs / Tutorials / Videos
I am really missing a "don't bother me at all about any exception during the current debug session" button. -
Patch 2 for RAD Studio 10.4 now available
Stefan Glienke replied to Marco Cantu's topic in General Help
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 -
Patch 2 for RAD Studio 10.4 now available
Stefan Glienke replied to Marco Cantu's topic in General Help
@Vincent Parrett Ewww looks like they made record constraint only allow record with no managed fields although things were just working -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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". -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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) -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
At least regarding life expectancy 😉 -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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. -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
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; -
Help with string extraction function
Stefan Glienke replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
@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...