Jump to content

Stefan Glienke

Members
  • Content Count

    1430
  • Joined

  • Last visited

  • Days Won

    141

Everything posted by Stefan Glienke

  1. Stefan Glienke

    Introducing Delphi Uses Helper

    Maybe the fact that I just can hit a shortcut and press enter in less than a second to add a uses without completely being disturbed by that UI? It's just a different mindset - I loved the way Visual Studio handled this with their quick action system and wanted it like that in Delphi as well. Maybe I am missing something but tell me the steps to add the containing unit once I declare a variable of type TWuppdi with GExperts. With UsesHelper while on TWuppdi I press Ctr+Shift+A Enter and the unit is in the uses.
  2. Stefan Glienke

    Delphi ignores path to unit in .dpr

    The order the compiler uses to find units is not the issue - the issue is that the compiler silently ignores the explicitly stated path to the source file in the uses clause of the dpr. And even if it has been the case since the dawn of time - does anyone really think that is a feature worth to have "I know you told me the file has to be at this exact location. But it was not so I just ignore it and look somewhere else, k?" Applying the principle of least astonishment to how the compiler deals with this situation would be to raise an error and tell the user that the file was not found where it was supposed to be. I am very sure this is more helpful than simply ignoring this information and look somewhere else to produce a successful compilation. In fact I even believe this is one of the many cases that lead to those dreaded dcu outdated errors because when you compile a pas the produced dcu is being put into the unit output directory. If you now move around your pas file but miss to change the path in the dpr/dpk because you don't do it in the IDE you might still succeed compiling because now the compiler uses the dcu from the output directory until things go out of sync and the dcu is outdated. Edit: I just tested this and unless the output dir is explicitly listed as search path this situation does not happen *unless* the unit is still open in the IDE regardless its existence in the file system.
  3. Stefan Glienke

    Delphi ignores path to unit in .dpr

    Unfortunately as far as I remember this has been an issue since ages and I once in a while step into that trap myself and shrug it off with "well, whatever". I am very sure it had been reported before but cannot find anything in JIRA right now - maybe it was in the old system - feel free to report it.
  4. Stefan Glienke

    Warning and Error at the same time?

    The correct word is "Warror", sometimes also called "Errning" /s
  5. Stefan Glienke

    casting an object as a interface via generic

    uses TypInfo; function TMyClass.MyFunc<T>: T; var p: PTypeData; begin p := GetTypeData(TypeInfo(T)); Assert(ifHasGuid in p.IntfFlags); Supports(Self, p.GUID, Result); end;
  6. Stefan Glienke

    Autocomplete behaviour: Delphi 10.4.2 VS Delphi 7

    Known issue: https://quality.embarcadero.com/browse/RSP-33118
  7. Stefan Glienke

    Delphi WAT of the day

  8. Stefan Glienke

    Min & Max

    Not that I know of because the compiler unfortunately does not utilize the cmovxx instruction. This has been reported already (I think there are other reports similar to this one): https://quality.embarcadero.com/browse/RSP-21955 Edit: Here is what clang and gcc generate: https://godbolt.org/z/4hnYrjYM6 And this is what Delphi generates: Project1.dpr.16: Result := min(i, 42); 00408F94 83F82A cmp eax,$2a 00408F97 7E05 jle $00408f9e 00408F99 B82A000000 mov eax,$0000002a Project1.dpr.17: end; 00408F9E C3 ret Project1.dpr.16: Result := min(i, 42); 000000000040D4F0 83F92A cmp ecx,$2a 000000000040D4F3 7F04 jnle Main + $9 000000000040D4F5 89C8 mov eax,ecx 000000000040D4F7 EB05 jmp Main + $E 000000000040D4F9 B82A000000 mov eax,$0000002a Project1.dpr.17: end; 000000000040D4FE C3 ret Yeah yeah branch predictors and all that - but if they are filled up with garbage conditional jumps like this they have less room for the important ones.
  9. Stefan Glienke

    Min & Max

    I am more annoyed with the unnecessary conditional jumps they generate and the fact they don't inline when using runtime packages
  10. It doesn't matter because 'AB' would be found first.
  11. No because the algo as I described is one pass, different from simply running ReplaceStr in a loop where subsequent replacements work on an altered input! Replace('Jabba the Hutt lived in a Hut', ['Hutt', 'Hut'], ['Alien', 'House']) would produce the same as would Replace('Jabba the Hutt lived in a Hut', ['Hut', 'Hutt'], ['House', 'Alien']) because finding the first 'Hut' from 'Hutt' would not eat the replacement to 'House' but continue and find a better match 'Hutt' to be replaced with 'Alien' and then be done with it.
  12. I brought that up in the third post in this thread already before everyone started polluting it with their attempts before actually knowing the exact requirements 😉 So assuming you want a one pass replacement of multiple matches using the best match I would try something like this: - sort replacement pairs by length of the to be replaced string descending (to get the best match first (like "hut" and "hutt" you would have "hutt" first to not replace "hut" where you could have replaced "hutt") - walk the input string char by char and check against the array of replacements if you have a match - due to the sorting by length you will find the most fitting one if there is any - produce output string on the fly copying the parts with no matches and the replacements I did not write any code for that nor did measure anything but that would be my approach
  13. Whether you decide is up to your own spec, but according to your testcase its a defect 🤷‍♂️
  14. A few notes: - the position array will very likely be rather short - unless you going to replace words in a novel or something like that. Handwritten InsertionSort will outperform that. - avoid dynamic allocation for the position array - use a static array with a reasonable standard size and only fall back to dynamically allocating if that is not enough - after fixing that I get an improvement of around 1/3 over the code you posted and now SamplingProfiler tells me that the code stays in System.Pos for like 50% of the time - that cannot be right Also you have a bug: AddTestCase(vTestCases, 'ReplaceReplaceString', ['Replace', 'FooString'], ['Foo', 'Bar']);
  15. First because 64bit does not suffer from the "virtual method glitch". Second because even with a class implementing the IComparer interface you get adjustor thunks which you don't have with the default comparers provided by Generics.Collections.Defaults because those are directly crafted IMTs (interface method tables) BTW: you again unnecessarily slow down your benchmark results by putting everything into the dpr main. And you are comparing different things - your CustomBinarySearch uses CompareValue which is a function call. So if you decide to roll your custom implementation then don't dumb it down: function GetName_CustomBinarySearch2(const aData: TArray<TDataLine>; const aItem: TDataLine): string; var L, H, i, c: Integer; begin L := 0; H := High(aData); while L <= H do begin i := L + (H - L) shr 1; c := aData[i].SeqNo - aItem.SeqNo; if c < 0 then L := i + 1 else if c > 0 then H := i - 1 else Break; end; if L <= H then Result := aData[i].CustomName else Result := ''; end; makes it almost twice as fast as your implementation. I decided to use the subtract approach as you did with the comparers - keep in mind this only works if there cant be an overflow which wont happen if SeqNo is just 0..MaxInt Anyhow at least in this benchmark it did not make any noticable difference to writing: if aData[i].SeqNo < aItem.SeqNo then L := i + 1 else if aData[i].SeqNo > aItem.SeqNo then H := i - 1 else Break;
  16. Stefan Glienke

    Profiler for Delphi

    Given its the "official" way to produce these files - I would not say that it's cheating. MS even published the "documentation" (as in "heres the code, figure it out yourself") on github: https://github.com/microsoft/microsoft-pdb It if turns out to be the best way then I could live with the fact that I have to install a VS - one would even have to check if distributing the required dll would be permitted or if just installing VS for using these dlls requires a license if you are not eligible to use the Community Edition.
  17. Stefan Glienke

    Profiler for Delphi

    Well shoot me all the stuff (with fool proof instructions if there are any ^^) and I try it out on VTune 2020
  18. Stefan Glienke

    Profiler for Delphi

    Just a few random thoughts: Could this be the case? https://community.intel.com/t5/Analyzers/Getting-Symbols-in-VTune-Amplifier-2018/td-p/1129907 Have you tried turning the pdb from the sample which seems to work into yaml, analyze is and turn it back into pdb to check if it still works? Like eliminating the differences between those two to nail down the case for VTune choking. Also in case you are not afraid of C++ you might look into https://github.com/rainers/cv2pdb which claims to be able to generate pdb files for D that Visual Studio can read (btw, can VS read yours?)
  19. FWIW the approach to use objects as bucket items for a hashmap is a no go in real code as your memory will be all over the place plus the memory overhead of objects. In a microbenchmark you will get away with that because there won't be much more memory around. On my i7 the TNameMap already drops behind the RTL dict at around 50000k items. The same seems to be the case for the TSynDict as that drops even more.
  20. Good point - I will even go even further and think all the lookup methods should returning rather than a specific property value which a) improves performance, b) makes them better comparable and c) makes this code more flexible Most then even turn into easily inlinable one liners.
  21. Stefan Glienke

    Profiler for Delphi

    It might be worth asking over on https://community.intel.com/t5/Analyzers/bd-p/analyzers. Maybe someone can give you a pointer into the right direction. Also did you try the pdb in WinDbg?
  22. As always you again seem to only read half of what I wrote. Base line (code as you posted) - running on an i5-3570K @ 3.4GHz Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 46 397 60 23 48 59 50 72 474 67 28 52 59 100 105 504 62 32 51 59 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 21 373 106 11 25 107 50 105 443 109 18 26 110 100 204 487 104 23 29 103 Use equalitycomparer from Tiny.Generics.pas for TDict and Spring - running on the i5-3570K @ 3.4GHz Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 45 407 44 24 49 44 50 71 468 42 27 48 42 100 96 499 43 32 53 43 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 21 379 26 11 27 25 50 106 445 25 18 27 25 100 207 483 26 22 29 27 Simply put "procedure Main;" after the CreateRandomData procedure and "end;begin Main;" before the end. - running on the i5-3570K @ 3.4GHz Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 28 387 27 25 32 26 50 51 455 25 28 32 24 100 76 487 27 32 34 27 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 22 380 27 12 25 27 50 105 446 24 18 28 24 100 207 489 25 24 30 26 Same code as before but running on an i7-8700 @ 3.2Ghz Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 23 306 21 20 27 20 50 42 355 22 24 28 20 100 63 377 22 26 29 21 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 17 299 16 7 18 17 50 72 359 16 13 19 17 100 139 383 17 21 22 18 Same code compiled with XE8 and also running on the i7-8700 @ 3.2GHz Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 26 292 22 20 24 21 50 65 342 22 23 26 21 100 112 355 21 25 26 23 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 24 281 17 8 18 18 50 116 331 18 13 20 18 100 215 347 17 16 22 17 Edit - for bonus points - I fixed the TArray.BinarySearch case by using an IComparer that I prepared and stored as field because that a) solves the return stack buffer glitch caused my TDelegatedComparer and b) avoids producing an anonymous method every time that method is being called. Also got rid of the CompareValue call in BinarySearchByID, can use < and >. Running on the i5-3570k @ 3.4Ghz Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 26 64 25 21 31 27 50 52 73 26 23 32 30 100 77 84 25 23 34 25 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 22 63 25 11 27 27 50 105 81 24 18 27 26 100 205 94 24 22 29 27
  23. As I already said - the high constant factor with the RTL hash function is the problem - both TDict and Spring with faster equalitycomparer from Tiny.Library - results from an i5-3570 @ 3.4GHz Also testing in the global main is garbage because you are then using global variables that cause way less optimal code - fixing that (simply put all that benchmark code into a procedure) and you get the following results Win32: Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 26 375 25 24 32 27 50 56 447 25 29 32 26 100 83 473 26 32 35 25 1000 535 585 28 83 37 26 10000 5561 753 46 130 44 30 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 21 382 28 12 30 27 50 109 466 24 18 28 25 100 206 491 24 23 31 26 1000 2044 603 30 88 39 30 10000 20532 810 36 181 49 36 Win64: Get Name from ID (Search by integer): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 24 297 26 23 32 26 50 60 323 26 30 31 26 100 94 328 26 40 32 26 1000 752 381 28 85 47 28 10000 8619 427 33 128 47 30 Get ID from Name (Search by string): records Sequenced TArray.BinS TDict CustomBinS TSynDict Spring 10 61 306 24 30 27 24 50 304 342 23 41 31 22 100 620 347 23 51 31 23 1000 6466 426 31 127 52 30 10000 64263 552 38 237 58 36
  24. Don't let yourself get distracted - I am eagerly awaiting your results Well it seems there is some DLL unload callback registered that clears the cache for that module should it exist. But given I understood the initial problem properly the case when the resourcestring was initially from the exe itself is not handled by that mechanism.
×