Jump to content

Stefan Glienke

Members
  • Content Count

    1437
  • Joined

  • Last visited

  • Days Won

    143

Everything posted by Stefan Glienke

  1. Stefan Glienke

    Get Index of enumeration in spring4D

    https://bitbucket.org/sglienke/spring4d/src/2.0.1/Source/Base/Collections/Spring.Collections.pas#lines-6391
  2. Stefan Glienke

    Get Index of enumeration in spring4D

    First of all, you can already achieve what you asked for in two different ways. (As I said, I will look into adding a similar method as .NET 9 did, but it's not as easy due to Delphi's limitations - it most likely will be a static method on TEnumerable and not on IEnumerable because it returns a differently typed IEnumerable, and that causes the Delphi compiler to complain with E2604.) Apart from the obvious use of a classic for-to loop if you already have an indexable collection such as IList where that new method IMHO would make no sense and just add overhead you can do this: var indexedColl := TEnumerable.Zip<Integer,TMyClass>(TEnumerable.Range(0, myColl.Count), myColl); for var curItem in indexedColl do Writeln('index: ', curItem.Value1, ' - item: ', curItem.Value2.ToString); If you want more control over index generation you can write this: var indexedColl := TEnumerable.Select<TMyClass, Tuple<Integer,TMyClass>>(myColl, function(const item: TMyClass; const index: Integer): Tuple<Integer,TMyClass> begin Result := Tuple<integer,TMyClass>.Create(index, item); end); for var curItem in indexedColl do Writeln('index: ', curItem.Value1, ' - item: ', curItem.Value2.ToString); If you then want to filter only certain indexes you just call Where on indexedColl: var oddIndexes := indexedColl.Where( function(const tuple: Tuple<Integer,TMyClass>): Boolean begin Result := Odd(tuple.Value1); end); for var curItem in oddIndexes do Writeln('index: ', curItem.Value1, ' - item: ', curItem.Value2.ToString);
  3. Stefan Glienke

    Get Index of enumeration in spring4D

    This would be a duplication of the already existing Where
  4. Stefan Glienke

    How to access/modify underlying records of IList<T>

    I have something like that in the works already. It does create a copy (records are value types, what else should it do?) - what you are proposing is dangerous and error-prone. That is not the case anymore in 2.0 - that interface has been removed from lists.
  5. Stefan Glienke

    Get Index of enumeration in spring4D

    No, but I see that .NET 9 added this. I might consider it.
  6. Stefan Glienke

    ISet<T> in spring4D

    FWIW if your type is an enum already it makes no sense to use ISet<T> because you can use the enum set. ISet<T> is for types that are no enums, such as string for example.
  7. Stefan Glienke

    Understanding DUnitX.Assert.WillRaise

    Passing parameters like that does not work in DUnitX - it silently ignores the string name for the exception class and then passes nil. Calling Assert.WillRaise with nil as exceptionClass succeeds when any exception was raised. @Vincent Parrett should be able to tell the best way to pass any parameters that cannot be easily converted from string.
  8. Stefan Glienke

    chatgpt can convert 32bit asm into 64bit

    Converting source code that won any challenge over 15 years ago is questionable regardless of correctness. Anyway, for this particular example, implementing a faster System.Move for Windows (other platforms use their libc memory) has been solved since Delphi 11.3. I sincerely challenge everyone to come up with a faster/better implementation.
  9. Stefan Glienke

    Strict type checking for tObject.

    It is pretty simple - imagine if the code below would work that way: procedure ReplacePet(var pet: TPet); begin pet.Free; pet := TCat.Create; end; procedure Main; var dog: TDog; begin ReplacePet(dog); dog.Bark; // meow?! end; FreeAndNil is special because it just destroys and assigns nil. But a var parameter does not give that guarantee.
  10. Stefan Glienke

    Double, default value

    Which - fun fact - does not happen on the method call (unless it's a virtual method) but when accessing any member inside of it. You could still have some method which does not access any member and it will not AV at all. We can argue all day about this - any runtime behavior one might slap onto it will not save the language from being inherently unsafe. It needs to be built into the language/compiler itself (Hi, Rust)
  11. Stefan Glienke

    Double, default value

    The main issue with memory safety in Delphi is not non-initialized local variables, which the compiler warns about, but use-after-free.
  12. Stefan Glienke

    Double, default value

    First, it's wrong to assume that all local variables reside on the stack, depending on optimization they might be in registers. Second, rep stosd is terribly slow for small sizes (see https://stackoverflow.com/a/33485055/587106 and also the discussions on this issue https://github.com/dotnet/runtime/issues/10744) Also, the Delphi compiler arranges managed local variables into one block that it zeroes (in many different and mostly terribly inefficient ways).
  13. Stefan Glienke

    Double, default value

    Why should the CPU waste time zeroing stuff that will be set shortly after anyway? Compilers are there to warn/error when any code path leads to a situation where a variable is not initialized.
  14. type TCustomItem = class; TCustomContainer = class abstract protected procedure HandleItemNotification(AItem: TCustomItem); virtual; abstract; end; TCustomItem = class protected FContainer: TCustomContainer; end; TCustomContainer<T: TCustomItem> = class abstract(TCustomContainer) protected FItems: TArray<T>; procedure HandleItemNotification(AItem: TCustomItem); overload; override; final; procedure HandleItemNotification(AItem: T); reintroduce; overload; end; TFooItem = class(TCustomItem) procedure SomeMethod; end; TFooContainer = class(TCustomContainer<TFooItem>); procedure TCustomContainer<T>.HandleItemNotification(AItem: T); begin // ... end; procedure TCustomContainer<T>.HandleItemNotification(AItem: TCustomItem); begin HandleItemNotification(T(AItem)); end; procedure TFooItem.SomeMethod; begin FContainer.HandleItemNotification(Self); end; var foo: TFooItem; begin foo := TFooItem.Create; foo.FContainer := TFooContainer.Create; foo.SomeMethod; end. I suggest moving as much code into the non generic base classes as possible. Given the constraint on TCustomItem this should even be reasonably easy to achieve. This will prevent causing larger than necessary binary sizes and longer than necessary compiletimes.
  15. Stefan Glienke

    Do you need an ARM64 compiler for Windows?

    Yes, pretty much - we all know they first ship a half-baked feature to generate marketing hype and then spend the next decade tinkering around the edges to make it work while representatives are telling us "eh, its complicated"
  16. It looks like whoever implemented that in the Delphi compiler was overly obsessed with codesize. If you compare what both gcc and clang do you can see that they rather produce a ton of mov instructions (which execute nicely in parallel on modern processors) before using memmov or rep: https://godbolt.org/z/Gjsqn7qas (change the size of the static array to see the assembly code change)
  17. Stefan Glienke

    win11 24h2 msheap fastest

    That benchmark proves almost (*) nothing, the only point where it allocates is during the form creation where it builds the card deck and later when it prints the output into the TListBox. (*) the only thing affected here is the possible layout of the card objects in the heap as they are all read during the hand-processing code. The difference that you can observe here between Delphi buids using different memory managers is most likely caused by the amount of overhead the respective memory manager is using thus fitting more card objects within the same memory pages, thus more of them (most likely all on modern processors) fitting into L1 cache. As for this particular code - removing the name of the Cards from the object and only building it when it is needed for some UI would probably speed up code more than anything else because you get rid of 20 Byte for every object (Name is a string[19]) - on my CPU this makes the code go down from ~900ms to ~680ms - simply because it does not need to copy the strings in CopyCardFromDeck. Circumventing the getter and setter of TList (which contribute around 25% of the remaining time) brings it down to 460ms. And after that we are not done with string stuff - in every loop iteration, it calls Hand.SetHighValues which produces a name for the cards on the hand - removing that gets me down to ~400. Now because I have a run and SamplingProfiler open already I see that now one of the scorers is TcaaPokerHand.CopyCardFromDeck - the Items getter is not inlined which causes it to be called 10 times for the same 2 card objects. Changing that gets me down to 270ms. But how about avoiding repeated access to the same object in the 2 lists altogether? 230ms I could go on because I see a lot more room to optimize - but I think I made my point. Instead of fiddling with the memory manager one should first look if heap allocations are even the issue. And then identify unnecessary work and eliminate that. ... change TcaaEvaluationCard to be 8 Byte size - (that avoids that the compiler creates a movsd/movsb instruction but simply does an 8 byte mov) -> 160ms
  18. Stefan Glienke

    String memory usage

    If you were using the RTL dictionary with its abysmal performance, that does not surprise me at all. Mostly because of its poor hash function, replacing that with a better one speeds it up significantly. However, string interning does not require a dictionary with key/value but just a hashtable for strings. DelphiAST has the option to use one for its parsing - we needed that when using it in the context of the IDE to avoid spikes in memory consumption.
  19. Clever way of introducing thread-unsafety 😉
  20. Stefan Glienke

    TParallelArray Sort Performance...

    Did you precompile Spring or are you compiling directly from the sources? If you precompile (recommended) then you need to precompile with release settings of course. If I had to bet I would say you still have range checking enabled (RTL has that disabled, so does your code) Also tbh I don't care about a 30% improvement of a handwritten algo specifically for one type over the generic one. Yes, compiler could do a better job with more aggressively inlining and stuff but nowadays I am happy already if it generates working code. Apart from the code not compiling I would say it depends on what you want to benchmark - how sort performs on completely cold data? Like some data that you loaded an hour ago, then did completely different things so it does not reside in the cache anymore and now you want to have the fastest sorting possible. Then yes, otherwise I would say that usually you typically are sorting data that is already in cache because you previously filled the array or list with it, or processed it followed by the sort operation. Some additional read on that "clear the LLC for some benchmark" topic: https://stackoverflow.com/a/49077734/587106
  21. Stefan Glienke

    TParallelArray Sort Performance...

    Here is something else to tease you all a bit - PDQSort is using comparer, PDQSort2 does not - others as before QuickSort2 is using the Spring Comparer - test type is Double: Looks like I am getting twice the speed at worst and 50 times at best. For faster to compare types such as Integer the gain goes up to almost 100 times. -------------------------------------------------------------------------------------- Benchmark Time CPU Iterations -------------------------------------------------------------------------------------- random/QuickSort/count:100 2917 ns 2886 ns 100 random/QuickSort2/count:100 2301 ns 2284 ns 100 random/IntroSort/count:100 1582 ns 1566 ns 100 random/PDQSort/count:100 1519 ns 1504 ns 100 random/PDQSort2/count:100 759 ns 746 ns 100 random/QuickSort/count:1000 48127 ns 47750 ns 100 random/QuickSort2/count:1000 26820 ns 26615 ns 100 random/IntroSort/count:1000 16349 ns 16157 ns 100 random/PDQSort/count:1000 24101 ns 23928 ns 100 random/PDQSort2/count:1000 6485 ns 6442 ns 100 random/QuickSort/count:10000 686240 ns 685846 ns 100 random/QuickSort2/count:10000 621977 ns 618258 ns 100 random/IntroSort/count:10000 426604 ns 426023 ns 100 random/PDQSort/count:10000 445646 ns 443871 ns 100 random/PDQSort2/count:10000 338404 ns 336588 ns 100 random/QuickSort/count:100000 8252128 ns 8220957 ns 100 random/QuickSort2/count:100000 7492506 ns 7371508 ns 100 random/IntroSort/count:100000 5723208 ns 5578393 ns 100 random/PDQSort/count:100000 5675312 ns 5650503 ns 100 random/PDQSort2/count:100000 4504745 ns 4482480 ns 100 random/QuickSort/count:1000000 98163494 ns 97011011 ns 100 random/QuickSort2/count:1000000 88461390 ns 87306397 ns 100 random/IntroSort/count:1000000 67687293 ns 66648855 ns 100 random/PDQSort/count:1000000 69019337 ns 68147235 ns 100 random/PDQSort2/count:1000000 55628991 ns 54791149 ns 100 few_unique/QuickSort/count:100 2356 ns 2314 ns 100 few_unique/QuickSort2/count:100 1540 ns 1500 ns 100 few_unique/IntroSort/count:100 1291 ns 1275 ns 100 few_unique/PDQSort/count:100 1559 ns 1483 ns 100 few_unique/PDQSort2/count:100 689 ns 674 ns 100 few_unique/QuickSort/count:1000 29073 ns 29009 ns 100 few_unique/QuickSort2/count:1000 16086 ns 16026 ns 100 few_unique/IntroSort/count:1000 11084 ns 11031 ns 100 few_unique/PDQSort/count:1000 8022 ns 7984 ns 100 few_unique/PDQSort2/count:1000 4015 ns 3983 ns 100 few_unique/QuickSort/count:10000 424766 ns 424046 ns 100 few_unique/QuickSort2/count:10000 292291 ns 288395 ns 100 few_unique/IntroSort/count:10000 224547 ns 222666 ns 100 few_unique/PDQSort/count:10000 145437 ns 144788 ns 100 few_unique/PDQSort2/count:10000 102878 ns 102414 ns 100 few_unique/QuickSort/count:100000 4654357 ns 4640420 ns 100 few_unique/QuickSort2/count:100000 3436405 ns 3421938 ns 100 few_unique/IntroSort/count:100000 2649901 ns 2639618 ns 100 few_unique/PDQSort/count:100000 1487662 ns 1479095 ns 100 few_unique/PDQSort2/count:100000 1172432 ns 1167015 ns 100 few_unique/QuickSort/count:1000000 51130249 ns 50537573 ns 100 few_unique/QuickSort2/count:1000000 38627555 ns 38033922 ns 100 few_unique/IntroSort/count:1000000 30907231 ns 30808893 ns 100 few_unique/PDQSort/count:1000000 14733627 ns 14572366 ns 100 few_unique/PDQSort2/count:1000000 12287426 ns 12233176 ns 100 two_values/QuickSort/count:100 2115 ns 2099 ns 100 two_values/QuickSort2/count:100 1601 ns 1558 ns 100 two_values/IntroSort/count:100 1058 ns 1037 ns 100 two_values/PDQSort/count:100 714 ns 699 ns 100 two_values/PDQSort2/count:100 395 ns 377 ns 100 two_values/QuickSort/count:1000 18838 ns 18787 ns 100 two_values/QuickSort2/count:1000 15509 ns 15468 ns 100 two_values/IntroSort/count:1000 10009 ns 9971 ns 100 two_values/PDQSort/count:1000 3434 ns 3397 ns 100 two_values/PDQSort2/count:1000 1715 ns 1673 ns 100 two_values/QuickSort/count:10000 310630 ns 306744 ns 100 two_values/QuickSort2/count:10000 221981 ns 214977 ns 100 two_values/IntroSort/count:10000 148667 ns 148595 ns 100 two_values/PDQSort/count:10000 42702 ns 42577 ns 100 two_values/PDQSort2/count:10000 24225 ns 24032 ns 100 two_values/QuickSort/count:100000 3353827 ns 3342019 ns 100 two_values/QuickSort2/count:100000 2487005 ns 2476672 ns 100 two_values/IntroSort/count:100000 1870906 ns 1863767 ns 100 two_values/PDQSort/count:100000 541802 ns 540355 ns 100 two_values/PDQSort2/count:100000 378254 ns 378023 ns 100 two_values/QuickSort/count:1000000 40114855 ns 39440910 ns 100 two_values/QuickSort2/count:1000000 29158407 ns 28744654 ns 100 two_values/IntroSort/count:1000000 23100678 ns 22744457 ns 100 two_values/PDQSort/count:1000000 5633201 ns 5601282 ns 100 two_values/PDQSort2/count:1000000 3762100 ns 3740864 ns 100 all_equal/QuickSort/count:100 2151 ns 2136 ns 100 all_equal/QuickSort2/count:100 1647 ns 1618 ns 100 all_equal/IntroSort/count:100 1058 ns 1040 ns 100 all_equal/PDQSort/count:100 570 ns 526 ns 100 all_equal/PDQSort2/count:100 326 ns 310 ns 100 all_equal/QuickSort/count:1000 17604 ns 17531 ns 100 all_equal/QuickSort2/count:1000 12558 ns 12503 ns 100 all_equal/IntroSort/count:1000 8658 ns 8607 ns 100 all_equal/PDQSort/count:1000 2501 ns 2517 ns 100 all_equal/PDQSort2/count:1000 1211 ns 1200 ns 100 all_equal/QuickSort/count:10000 229287 ns 228053 ns 100 all_equal/QuickSort2/count:10000 168158 ns 167545 ns 100 all_equal/IntroSort/count:10000 123868 ns 122653 ns 100 all_equal/PDQSort/count:10000 17648 ns 17566 ns 100 all_equal/PDQSort2/count:10000 6898 ns 6844 ns 100 all_equal/QuickSort/count:100000 3089106 ns 2839190 ns 100 all_equal/QuickSort2/count:100000 1991645 ns 1983108 ns 100 all_equal/IntroSort/count:100000 1517401 ns 1509352 ns 100 all_equal/PDQSort/count:100000 168092 ns 167526 ns 100 all_equal/PDQSort2/count:100000 64056 ns 63376 ns 100 all_equal/QuickSort/count:1000000 31780316 ns 31401768 ns 100 all_equal/QuickSort2/count:1000000 23670745 ns 23308078 ns 100 all_equal/IntroSort/count:1000000 18492352 ns 18165700 ns 100 all_equal/PDQSort/count:1000000 1693063 ns 1685270 ns 100 all_equal/PDQSort2/count:1000000 667052 ns 665049 ns 100 ascending/QuickSort/count:100 1645 ns 1629 ns 100 ascending/QuickSort2/count:100 1249 ns 1233 ns 100 ascending/IntroSort/count:100 993 ns 956 ns 100 ascending/PDQSort/count:100 524 ns 510 ns 100 ascending/PDQSort2/count:100 290 ns 276 ns 100 ascending/QuickSort/count:1000 15279 ns 15237 ns 100 ascending/QuickSort2/count:1000 11455 ns 11389 ns 100 ascending/IntroSort/count:1000 7931 ns 7802 ns 100 ascending/PDQSort/count:1000 2618 ns 2572 ns 100 ascending/PDQSort2/count:1000 1199 ns 1169 ns 100 ascending/QuickSort/count:10000 186722 ns 185998 ns 100 ascending/QuickSort2/count:10000 134269 ns 134014 ns 100 ascending/IntroSort/count:10000 106604 ns 106492 ns 100 ascending/PDQSort/count:10000 19298 ns 19236 ns 100 ascending/PDQSort2/count:10000 6002 ns 5953 ns 100 ascending/QuickSort/count:100000 2229729 ns 2219903 ns 100 ascending/QuickSort2/count:100000 1655304 ns 1647404 ns 100 ascending/IntroSort/count:100000 1298027 ns 1291995 ns 100 ascending/PDQSort/count:100000 190239 ns 189988 ns 100 ascending/PDQSort2/count:100000 53607 ns 53501 ns 100 ascending/QuickSort/count:1000000 27509633 ns 27165759 ns 100 ascending/QuickSort2/count:1000000 19985236 ns 19668315 ns 100 ascending/IntroSort/count:1000000 15326770 ns 15254001 ns 100 ascending/PDQSort/count:1000000 1901178 ns 1890171 ns 100 ascending/PDQSort2/count:1000000 629675 ns 628905 ns 100 slightly_scrambled/QuickSort/count:100 1750 ns 1732 ns 100 slightly_scrambled/QuickSort2/count:100 1373 ns 1343 ns 100 slightly_scrambled/IntroSort/count:100 985 ns 968 ns 100 slightly_scrambled/PDQSort/count:100 1012 ns 997 ns 100 slightly_scrambled/PDQSort2/count:100 471 ns 454 ns 100 slightly_scrambled/QuickSort/count:1000 16791 ns 16735 ns 100 slightly_scrambled/QuickSort2/count:1000 12824 ns 12776 ns 100 slightly_scrambled/IntroSort/count:1000 10458 ns 10399 ns 100 slightly_scrambled/PDQSort/count:1000 16268 ns 15887 ns 100 slightly_scrambled/PDQSort2/count:1000 4547 ns 4494 ns 100 slightly_scrambled/QuickSort/count:10000 235073 ns 233521 ns 100 slightly_scrambled/QuickSort2/count:10000 200321 ns 199399 ns 100 slightly_scrambled/IntroSort/count:10000 151789 ns 151249 ns 100 slightly_scrambled/PDQSort/count:10000 174541 ns 173592 ns 100 slightly_scrambled/PDQSort2/count:10000 89454 ns 89257 ns 100 slightly_scrambled/QuickSort/count:100000 2972211 ns 2964870 ns 100 slightly_scrambled/QuickSort2/count:100000 2376263 ns 2366504 ns 100 slightly_scrambled/IntroSort/count:100000 2305909 ns 2052472 ns 100 slightly_scrambled/PDQSort/count:100000 2093171 ns 2083240 ns 100 slightly_scrambled/PDQSort2/count:100000 982124 ns 978410 ns 100 slightly_scrambled/QuickSort/count:1000000 35292840 ns 34939068 ns 100 slightly_scrambled/QuickSort2/count:1000000 29451877 ns 28875217 ns 100 slightly_scrambled/IntroSort/count:1000000 25058823 ns 24750291 ns 100 slightly_scrambled/PDQSort/count:1000000 25962367 ns 25535252 ns 100 slightly_scrambled/PDQSort2/count:1000000 12483234 ns 12181630 ns 100 sorted_blocks/QuickSort/count:100 2430 ns 2405 ns 100 sorted_blocks/QuickSort2/count:100 2499 ns 2478 ns 100 sorted_blocks/IntroSort/count:100 1061 ns 1019 ns 100 sorted_blocks/PDQSort/count:100 1329 ns 1285 ns 100 sorted_blocks/PDQSort2/count:100 720 ns 652 ns 100 sorted_blocks/QuickSort/count:1000 16224 ns 16169 ns 100 sorted_blocks/QuickSort2/count:1000 19509 ns 19454 ns 100 sorted_blocks/IntroSort/count:1000 14560 ns 14515 ns 100 sorted_blocks/PDQSort/count:1000 9479 ns 9313 ns 100 sorted_blocks/PDQSort2/count:1000 4913 ns 4885 ns 100 sorted_blocks/QuickSort/count:10000 308032 ns 306791 ns 100 sorted_blocks/QuickSort2/count:10000 238446 ns 238183 ns 100 sorted_blocks/IntroSort/count:10000 173146 ns 172243 ns 100 sorted_blocks/PDQSort/count:10000 168365 ns 166934 ns 100 sorted_blocks/PDQSort2/count:10000 65434 ns 65356 ns 100 sorted_blocks/QuickSort/count:100000 4041913 ns 4028550 ns 100 sorted_blocks/QuickSort2/count:100000 3239075 ns 3226690 ns 100 sorted_blocks/IntroSort/count:100000 2578785 ns 2434971 ns 100 sorted_blocks/PDQSort/count:100000 2386599 ns 2375001 ns 100 sorted_blocks/PDQSort2/count:100000 966824 ns 959131 ns 100 sorted_blocks/QuickSort/count:1000000 51596313 ns 50949966 ns 100 sorted_blocks/QuickSort2/count:1000000 39977951 ns 39455223 ns 100 sorted_blocks/IntroSort/count:1000000 29587960 ns 29072445 ns 100 sorted_blocks/PDQSort/count:1000000 29140836 ns 28926711 ns 100 sorted_blocks/PDQSort2/count:1000000 13950878 ns 13703237 ns 100 single_big_swap/QuickSort/count:100 1290 ns 1277 ns 100 single_big_swap/QuickSort2/count:100 1004 ns 1000 ns 100 single_big_swap/IntroSort/count:100 1087 ns 1069 ns 100 single_big_swap/PDQSort/count:100 633 ns 620 ns 100 single_big_swap/PDQSort2/count:100 474 ns 456 ns 100 single_big_swap/QuickSort/count:1000 16889 ns 16794 ns 100 single_big_swap/QuickSort2/count:1000 12697 ns 12655 ns 100 single_big_swap/IntroSort/count:1000 14016 ns 13967 ns 100 single_big_swap/PDQSort/count:1000 7008 ns 6939 ns 100 single_big_swap/PDQSort2/count:1000 2342 ns 2339 ns 100 single_big_swap/QuickSort/count:10000 204246 ns 204182 ns 100 single_big_swap/QuickSort2/count:10000 156179 ns 155306 ns 100 single_big_swap/IntroSort/count:10000 192030 ns 190639 ns 100 single_big_swap/PDQSort/count:10000 78781 ns 78285 ns 100 single_big_swap/PDQSort2/count:10000 23238 ns 23145 ns 100 single_big_swap/QuickSort/count:100000 2414905 ns 2395809 ns 100 single_big_swap/QuickSort2/count:100000 1787565 ns 1778945 ns 100 single_big_swap/IntroSort/count:100000 2523279 ns 2517094 ns 100 single_big_swap/PDQSort/count:100000 889865 ns 884869 ns 100 single_big_swap/PDQSort2/count:100000 249087 ns 246596 ns 100 single_big_swap/QuickSort/count:1000000 29262380 ns 28791769 ns 100 single_big_swap/QuickSort2/count:1000000 21306314 ns 20978264 ns 100 single_big_swap/IntroSort/count:1000000 30104774 ns 29736630 ns 100 single_big_swap/PDQSort/count:1000000 10839585 ns 10689165 ns 100 single_big_swap/PDQSort2/count:1000000 3153072 ns 3134668 ns 100 descending/QuickSort/count:100 1633 ns 1619 ns 100 descending/QuickSort2/count:100 1324 ns 1245 ns 100 descending/IntroSort/count:100 915 ns 904 ns 100 descending/PDQSort/count:100 534 ns 518 ns 100 descending/PDQSort2/count:100 305 ns 290 ns 100 descending/QuickSort/count:1000 15212 ns 15109 ns 100 descending/QuickSort2/count:1000 12131 ns 12071 ns 100 descending/IntroSort/count:1000 8520 ns 8483 ns 100 descending/PDQSort/count:1000 2677 ns 2616 ns 100 descending/PDQSort2/count:1000 1168 ns 1167 ns 100 descending/QuickSort/count:10000 190983 ns 190004 ns 100 descending/QuickSort2/count:10000 142282 ns 141461 ns 100 descending/IntroSort/count:10000 106956 ns 106801 ns 100 descending/PDQSort/count:10000 22199 ns 22098 ns 100 descending/PDQSort2/count:10000 7163 ns 6853 ns 100 descending/QuickSort/count:100000 2210157 ns 2201096 ns 100 descending/QuickSort2/count:100000 1639887 ns 1632072 ns 100 descending/IntroSort/count:100000 1308584 ns 1301543 ns 100 descending/PDQSort/count:100000 186613 ns 185900 ns 100 descending/PDQSort2/count:100000 56812 ns 56648 ns 100 descending/QuickSort/count:1000000 27759185 ns 27197419 ns 100 descending/QuickSort2/count:1000000 19937923 ns 19733711 ns 100 descending/IntroSort/count:1000000 15222011 ns 15155862 ns 100 descending/PDQSort/count:1000000 2159517 ns 1899555 ns 100 descending/PDQSort2/count:1000000 560522 ns 557461 ns 100 pipe_organ/QuickSort/count:100 1853 ns 1835 ns 100 pipe_organ/QuickSort2/count:100 1439 ns 1416 ns 100 pipe_organ/IntroSort/count:100 1029 ns 950 ns 100 pipe_organ/PDQSort/count:100 528 ns 517 ns 100 pipe_organ/PDQSort2/count:100 296 ns 282 ns 100 pipe_organ/QuickSort/count:1000 15940 ns 15886 ns 100 pipe_organ/QuickSort2/count:1000 11960 ns 11911 ns 100 pipe_organ/IntroSort/count:1000 8271 ns 8225 ns 100 pipe_organ/PDQSort/count:1000 2622 ns 2591 ns 100 pipe_organ/PDQSort2/count:1000 1192 ns 1172 ns 100 pipe_organ/QuickSort/count:10000 193559 ns 193175 ns 100 pipe_organ/QuickSort2/count:10000 150531 ns 149370 ns 100 pipe_organ/IntroSort/count:10000 115439 ns 115205 ns 100 pipe_organ/PDQSort/count:10000 19195 ns 19176 ns 100 pipe_organ/PDQSort2/count:10000 6117 ns 6021 ns 100 pipe_organ/QuickSort/count:100000 2486991 ns 2478769 ns 100 pipe_organ/QuickSort2/count:100000 1819950 ns 1810639 ns 100 pipe_organ/IntroSort/count:100000 1388682 ns 1383509 ns 100 pipe_organ/PDQSort/count:100000 190331 ns 188891 ns 100 pipe_organ/PDQSort2/count:100000 52793 ns 52639 ns 100 pipe_organ/QuickSort/count:1000000 29577606 ns 29326755 ns 100 pipe_organ/QuickSort2/count:1000000 21748586 ns 21414611 ns 100 pipe_organ/IntroSort/count:1000000 16696194 ns 16630029 ns 100 pipe_organ/PDQSort/count:1000000 1869925 ns 1864242 ns 100 pipe_organ/PDQSort2/count:1000000 549429 ns 545797 ns 100 push_front/QuickSort/count:100 2289 ns 2269 ns 100 push_front/QuickSort2/count:100 1478 ns 1491 ns 100 push_front/IntroSort/count:100 1605 ns 1561 ns 100 push_front/PDQSort/count:100 1282 ns 1240 ns 100 push_front/PDQSort2/count:100 543 ns 523 ns 100 push_front/QuickSort/count:1000 18117 ns 18055 ns 100 push_front/QuickSort2/count:1000 15428 ns 15155 ns 100 push_front/IntroSort/count:1000 14087 ns 13988 ns 100 push_front/PDQSort/count:1000 12455 ns 12404 ns 100 push_front/PDQSort2/count:1000 4450 ns 4413 ns 100 push_front/QuickSort/count:10000 229186 ns 227644 ns 100 push_front/QuickSort2/count:10000 160690 ns 160380 ns 100 push_front/IntroSort/count:10000 191233 ns 190610 ns 100 push_front/PDQSort/count:10000 145472 ns 144255 ns 100 push_front/PDQSort2/count:10000 41785 ns 41612 ns 100 push_front/QuickSort/count:100000 2922293 ns 2702687 ns 100 push_front/QuickSort2/count:100000 1923425 ns 1917358 ns 100 push_front/IntroSort/count:100000 2488440 ns 2478518 ns 100 push_front/PDQSort/count:100000 1688943 ns 1681909 ns 100 push_front/PDQSort2/count:100000 466741 ns 465112 ns 100 push_front/QuickSort/count:1000000 31411786 ns 31044262 ns 100 push_front/QuickSort2/count:1000000 22438347 ns 22338651 ns 100 push_front/IntroSort/count:1000000 30187199 ns 29784770 ns 100 push_front/PDQSort/count:1000000 19681892 ns 19340073 ns 100 push_front/PDQSort2/count:1000000 5359031 ns 5330950 ns 100 push_middle/QuickSort/count:100 1986 ns 1972 ns 100 push_middle/QuickSort2/count:100 1523 ns 1475 ns 100 push_middle/IntroSort/count:100 1198 ns 1155 ns 100 push_middle/PDQSort/count:100 982 ns 965 ns 100 push_middle/PDQSort2/count:100 437 ns 419 ns 100 push_middle/QuickSort/count:1000 16948 ns 16891 ns 100 push_middle/QuickSort2/count:1000 12581 ns 12432 ns 100 push_middle/IntroSort/count:1000 10488 ns 10440 ns 100 push_middle/PDQSort/count:1000 4969 ns 4929 ns 100 push_middle/PDQSort2/count:1000 2006 ns 1953 ns 100 push_middle/QuickSort/count:10000 206586 ns 206205 ns 100 push_middle/QuickSort2/count:10000 147860 ns 147583 ns 100 push_middle/IntroSort/count:10000 143688 ns 143232 ns 100 push_middle/PDQSort/count:10000 44343 ns 44226 ns 100 push_middle/PDQSort2/count:10000 14500 ns 14441 ns 100 push_middle/QuickSort/count:100000 2641267 ns 2493017 ns 100 push_middle/QuickSort2/count:100000 1782662 ns 1775961 ns 100 push_middle/IntroSort/count:100000 1867750 ns 1861113 ns 100 push_middle/PDQSort/count:100000 426423 ns 423756 ns 100 push_middle/PDQSort2/count:100000 121412 ns 120541 ns 100 push_middle/QuickSort/count:1000000 29463664 ns 29094682 ns 100 push_middle/QuickSort2/count:1000000 21699498 ns 21338872 ns 100 push_middle/IntroSort/count:1000000 22344304 ns 21994267 ns 100 push_middle/PDQSort/count:1000000 4514580 ns 4247772 ns 100 push_middle/PDQSort2/count:1000000 1244558 ns 1236921 ns 100
  22. Stefan Glienke

    TParallelArray Sort Performance...

    Benchmark code: {$APPTYPE CONSOLE} uses System.Diagnostics, System.Generics.Collections, System.SysUtils, Spring; procedure Test(count: NativeInt); var SSortArray, PSortArray: TArray<double>; I: Integer; T: TStopwatch; begin try SetLength(SSortArray, count); SetLength(PSortArray, count); Writeln('Fill array (double), elements count: ', count); for I := Low(SSortArray) to High(SSortArray) do begin SSortArray[I] := Random(MaxInt); PSortArray[I] := SSortArray[I]; end; Writeln('Start sorting ...'); T := TStopwatch.StartNew; System.Generics.Collections.TArray.Sort<double>(SSortArray); T.Stop; Writeln('RTL TArray.Sort (ms.): ', T.ElapsedMilliseconds.ToString); T := TStopwatch.StartNew; Spring.TArray.Sort<double>(PSortArray); T.Stop; Writeln('Spring TArray.Sort (ms.): ', T.ElapsedMilliseconds.ToString); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Writeln; end; begin Test(500_000); Test(5_000_000); Test(100_000_000); Readln; end. Results (win64 release) on i7-12700: Fill array (double), elements count: 500000 Start sorting ... RTL TArray.Sort (ms.): 49 Spring TArray.Sort (ms.): 33 Fill array (double), elements count: 5000000 Start sorting ... RTL TArray.Sort (ms.): 560 Spring TArray.Sort (ms.): 393 Fill array (double), elements count: 100000000 Start sorting ... RTL TArray.Sort (ms.): 13053 Spring TArray.Sort (ms.): 9351
  23. Stefan Glienke

    TParallelArray Sort Performance...

    To me they are not - if you have some backend server code that is already doing multiple things in parallel it won't get any better if you then do parallel sort.
  24. Stefan Glienke

    TParallelArray Sort Performance...

    The issue is that in the Parallel implementation there is no mitigation against QuickSorts well known worst case.
  25. Stefan Glienke

    TParallelArray Sort Performance...

    This is the benchmark code - previous results I posted were with TTestType = Integer, but using Double shows similar results (I ran the benchmark as 64bit release) program SortBench; {$APPTYPE CONSOLE} uses System.Generics.Collections, Spring, Spring.Comparers, Spring.Benchmark, System.SysUtils; type TTestType = Double; TDistFunc = function(size: Integer): TArray<TTestType>; TSortFunc = procedure(var values: array of TTestType); function IntToTestType(i: Integer): TTestType; begin Result := i; end; function Equals(const left, right: TTestType): Boolean; inline; begin Result := left = right; end; function Shuffled(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(i); Spring.TArray.Shuffle<TTestType>(Result); end; function Shuffled_16Values(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(Random(16)); end; function TwoValues(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(Random(2)); end; function AllEqual(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(0); end; function Ascending(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(i); end; function SlightlyScrambled(size: Integer): TArray<TTestType>; const scramblePercentage = 5; var i, idx1, idx2: Integer; temp: TTestType; scrambleCount: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(i); scrambleCount := size * scramblePercentage div 100; for i := 1 to scrambleCount do begin idx1 := Random(size); idx2 := Random(size); temp := Result[idx1]; Result[idx1] := Result[idx2]; Result[idx2] := temp; end; end; function SortedBlocks(size: Integer): TArray<TTestType>; type TBlock100 = array[1..100] of TTestType; TBlock10 = array[1..10] of TTestType; var i: Integer; begin SetLength(Result, size); for i := 0 to size - 1 do Result[i] := IntToTestType(i); if size > 100 then Spring.TArray.Shuffle<TBlock100>(Pointer(Result), (size div (SizeOf(TBlock100) div SizeOf(TTestType))) - 1) else Spring.TArray.Shuffle<TBlock10>(Pointer(Result), (size div (SizeOf(TBlock10) div SizeOf(TTestType))) - 1); end; function SingleBigSwap(size: Integer): TArray<TTestType>; var i: Integer; halfSize: Integer; begin SetLength(Result, size); halfSize := size div 2; for i := 0 to halfSize - 1 do Result[i] := IntToTestType(i + halfSize); for i := halfSize to size -1 do Result[i] := IntToTestType(i - halfSize); end; function Descending(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := size-1 downto 0 do Result[i] := IntToTestType(i); end; function PipeOrgan(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to (size div 2) - 1 do Result[i] := IntToTestType(i); for i := size div 2 to size -1 do Result[i] := IntToTestType(size - 1); end; function PushFront(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 1 to size - 1 do Result[i - 1] := IntToTestType(i); Result[size - 1] := IntToTestType(0); end; function PushMiddle(size: Integer): TArray<TTestType>; var i: Integer; begin SetLength(Result, size); for i := 0 to (size div 2) - 1 do Result[i] := IntToTestType(i); for i := (size div 2) + 1 to size -1 do Result[i - 1] := IntToTestType(i); Result[size - 1] := IntToTestType(size div 2); end; procedure QuickSort(var values: array of TTestType); begin System.Generics.Collections.TArray.Sort<TTestType>(values); end; procedure QuickSort_SpringComparer(var values: array of TTestType); begin System.Generics.Collections.TArray.Sort<TTestType>(values , Spring.Comparers.TComparer<TTestType>.Default ); end; procedure IntroSort(var values: array of TTestType); begin Spring.TArray.Sort<TTestType>(values); end; const Distributions: array[0..11] of record name: string; func: TDistFunc end = ( (name: 'random'; func: Shuffled), (name: 'few_unique'; func: Shuffled_16Values), (name: 'two_values'; func: TwoValues), (name: 'all_equal'; func: AllEqual), (name: 'ascending'; func: Ascending), (name: 'slightly_scrambled'; func: SlightlyScrambled), (name: 'sorted_blocks'; func: SortedBlocks), (name: 'single_big_swap'; func: SingleBigSwap), (name: 'descending'; func: Descending), (name: 'pipe_organ'; func: PipeOrgan), (name: 'push_front'; func: PushFront), (name: 'push_middle'; func: PushMiddle) ); Sorts: array[0..2] of record name: string; func: TSortFunc end = ( (name: 'QuickSort'; func: QuickSort) ,(name: 'QuickSort2'; func: QuickSort_SpringComparer) ,(name: 'IntroSort'; func: IntroSort) ); Sizes: array of Integer = [100, 1000, 10000, 100000, 1000000]; procedure BenchSort(const state: TState); begin var distIdx := state[0]; var sortIdx := state[1]; var size := state[2]; var distribution: TDistFunc := Distributions[distIdx].func; var sort: TSortFunc := Sorts[sortIdx].func; var data := distribution(size); var copy: TArray<TTestType>; SetLength(copy, size); for var _ in state do begin state.PauseTiming; if IsManagedType(TTestType) then MoveManaged(data, copy, TypeInfo(TTestType), size) else Move(data[0], copy[0], size * SizeOf(TTestType)); state.ResumeTiming; sort(copy); end; QuickSort(data); for var i := 0 to high(copy) do Assert(Equals(copy[i], data[i]), Distributions[distIdx].Name + '/' + Sorts[sortIdx].Name + '/' + size.ToString); end; procedure Main; begin benchmark_format_args := False; for var distIdx := Low(distributions) to High(Distributions) do for var size in Sizes do for var sortIdx := Low(Sorts) to High(Sorts) do begin var bm := Benchmark(BenchSort, Distributions[distIdx].name + '/' + Sorts[sortIdx].name + '/count:' + size.ToString) .Args([distIdx, sortIdx, size]); bm.Iterations(100); end; Benchmark_Main; end; begin try Main; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end.
×