Jump to content

Stefan Glienke

Members
  • Content Count

    1366
  • Joined

  • Last visited

  • Days Won

    130

Everything posted by Stefan Glienke

  1. Stefan Glienke

    Hex2Binary

    Especially since one of its selling points is "it compiles to native code" - if that native code is garbage for modern CPUs because its written like in the 90s that's kinda poor.
  2. Stefan Glienke

    Hex2Binary

    Fair enough - guess I have to go back to the version with the label.
  3. Stefan Glienke

    Hex2Binary

    Close one, nice! 😉 But I would be surprised if a simd loop would not beat it. I am sure doing the entire thing with a simd loop would totally destroy any pure pascal solution.
  4. Stefan Glienke

    Hex2Binary

    That was a typo that David copied - my first version had 3 checks in the loop where {$B+} made it better, now with only 2 checks I don't need that anymore - see my post with the currently best version.
  5. Stefan Glienke

    Hex2Binary

    Well that is the optimizations that some people were aware of and some weren't - why would that be unfair? P.S. What did I win? Joking aside - it's always interesting that different people see different things. And at the same time it's very sad that perfectly fine code will be like 3-4 times slower than hardcore optimized code simply because the compiler does not know about some things, does not do zero cost abstractions (*) and does not reorder code to make it better. (*) I mean seriously - why do an LStrAsg on a string parameter - as if that would go invalid in the middle of the loop or what?! And because you cannot assign to a loop variable it should treat it exactly the same way as a moving PChar over the string.
  6. Stefan Glienke

    Hex2Binary

    "Get your conditional jumps and error handling garbage outta my hot loop, kay?" function HexToBinStefan(const HexValue: string): string; // put the exception stuff into a subroutine to not pollute our routine procedure Error(c: PChar; s: string); begin raise EConvertError.CreateFmt('Invalid hex digit ''%s'' found in ''%s''', [c^, s]); end; label _Error; type TChar4 = array[0..3] of Char; PChar4 = ^TChar4; {$POINTERMATH ON} PInteger = ^Integer; {$POINTERMATH OFF} const Table: array[0..22] of TChar4 = ( '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', // 0-9 'xxxx', 'xxxx', 'xxxx', 'xxxx', 'xxxx', 'xxxx', 'xxxx', // :-@ - unused '1010', '1011', '1100', '1101', '1110', '1111'); // A-F var HexDigit: PChar; P: PChar4; i, n: Cardinal; begin // do not use PChar cast because that causes a call to UStrToPWChar // we don't need that special PChar to #0 when HexValue is empty HexDigit := Pointer(HexValue); if HexDigit = nil then Exit; // we know that HexDigit is not nil so we can avoid the conditional jump from Length // this also directly moves it into the correct register for the SetLength call SetLength(Result, PInteger(HexDigit)[-1] * 4); P := PChar4(Result); for i := 1 to PInteger(HexDigit)[-1] do begin // subtract 48 to make '0'-'9' 0-9 which enables unconditionally downcasing any upper case char // when we hit the #0 it will simply produce an invalid value for n that we will break on next n := Cardinal(Integer(Ord(HexDigit^)) - 48) and not 32; // avoid one check by simply subtracting 10 and checking the invalid range of 10-16 // thank you godbolt.org and amazingly optimizing c++ compilers for that idea! <3 if (Cardinal(Integer(n)-10) <= 6) or (n > 22) then goto _error; P^ := Table[n]; Inc(P); Inc(HexDigit); end; Exit; _error: Error(HexDigit, HexValue); end;
  7. Stefan Glienke

    Hex2Binary

    i was just going to comment on that - a for in loop on a string is causing the compiler to do an LStrAsg to a local variable and iterates that one which causes a costly implicit try finally and UstrClr in the epilogue. Also with all that microbenchmarking - please consider the compiler might place code for various implementations good or bad in terms of their layout within cache lines. We had that topic already some while ago where one implementation was simply faster because the hot loop fit into one cache line while another one or even rearranging of code caused it to span two cache lines affecting the results negatively.
  8. Stefan Glienke

    Hex2Binary

    Kinda pointless to limit the power of sse to handling single characters instead of simply processing multiple characters at once - especially since you now have a call inside the loop slowing stuff down significantly plus having to move the same stuff over and over into xmm2-4. Using simd should be 2-10times faster than the regular 1 char in a loop implementation
  9. Stefan Glienke

    Hex2Binary

    Certainly not in a microbenchmark where probably everything fits into L1 cache. Not so in a real program where that array of string might be placed in different locations than the strings it contains.
  10. Stefan Glienke

    Default value

    Interesting - I think I am going to add that to the TManagedObject functionality
  11. Stefan Glienke

    Default value

    uses Spring; type TExample = class(TManagedObject) [Default(-1)] Index: integer; end; Just because I can 😎
  12. Stefan Glienke

    64 bit compiler running out of memory

    Kids these days - making them 64bit would be the lazy solution - being more reasonable with allocating memory would be the good one. Especially with confirmed performance issues in the compiler that are caused by unnecessary heap allocations.
  13. I think everyone knows what happens in the following code: {$APPTYPE CONSOLE} {$RANGECHECKS OFF} uses Classes, Generics.Collections, SysUtils; var s: TStringList; l: TList<Integer>; begin s := TStringList.Create; try Writeln(s[0]); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; s.Free; l := TList<Integer>.Create; try Writeln(l[0]); except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; l.Free; Readln; end. Spoiler: EStringListError: List index out of bounds (0) EArgumentOutOfRangeException: Argument out of range Now we can argue if that is good or bad that regardless the rangecheck option the code in those lists always does range checking but the question I am pondering over is the following: Do I as a 3rd party library author where users can compile its code to their liking want to have the same behavior or do I want to make the range checking for index and count parameters in collection classes to depend on {$IFOPT R+} (or some other define) and let the person compiling the code decide if they want to have the range checking or not? Your suggestions and opinions are welcome. Before someone suggests it - due to possibly overallocating storage arrays and that you cannot simply rely on the range checking the compiler inserts with {$R+}
  14. Stefan Glienke

    do any git tools work like this?

    Must be very unproductive and frustrating the way you handle things - it is known that humans are terrible at context switching.
  15. There are several factors - RTTI is one of them, another is generics, in combination they can be quite terrible. Example: A class is using a TList<something> as a field - TList<T> has RTTI enabled which causes all code for that TList<something> to reside inside the binary even though calls to Add, Delete and alike are inlined and go directly to those non generic TListHelper methods. Now multiply that with all lists and dictionaries in RTL/VCL and your code and you have the issue. Having said that - this is just one case which I was working on as author of a library that makes extensive use of generics and I don't want to be a big contributor to that issue. Putting {$WEAKLINKRTTI ON} into the project file can reduce the bloat a bit because this enables the linker to remove all methods that are not being used. An empty FMX application on Win32 is 8.5MB in release config and contains way over 2MB just from System.Generics.*. With that option you can at least reduce this to 7.4MB (numbers from Delphi 10.1). How that option affects your code depends on your code. During the development of Spring4D I rigorously have used {$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}{$ENDIF} in a lot of units to at least reduce any bloat from my code but without recompiling the RTL/VCL/FMX you cannot do that for the Delphi code.
  16. A method is a routine (procedure/function) that is associated with an object. A class method would be a routine (procedure/function) that is associated with a class.
  17. @Kas Ob. Not strange at all (maybe a bit misleading UI I admit), what you download there is the source of a specific commit (the lastest master, which would not contain timsort btw, surprise) - repository size includes the entire history. If you want to not use git as intended then you need to switch to the branches tab and there select one of the download options.
  18. @David Heffernan and me implemented one for Spring4D - you can already check it out in the develop branch
  19. Stefan Glienke

    function reference feature for Delphi source code

    This feature is called CodeLens - if you fancy you can look on GitHub how its implemented in VSCode.
  20. Stefan Glienke

    Having fun with Delphi

    A string builder must be created and more importantly destroyed. Unless you are making this a custom managed record (which would be equally terrible for fluent API I guess - not tested yet) you would then need to explicitly call some Release/Free/whatever method on that record. If you were to make a fluent API on a record storing all the information those API methods must work with a reference type (such as the pointer to that record) but that makes this API a bit less convenient when you just want to store that result to a variable of that record type (would need an extra call or a deref after the last method call)
  21. Stefan Glienke

    Having fun with Delphi

    Fluent API with records containing managed fields (such as strings) unfortunately produces terrible code because the compiler produces an implicit variable for each method call.
  22. I really lol'ed at that one - stockholm syndrome anyone?
  23. The description is in the paper and the reference implementation in c is in the very links on that page. Attention though: there is xoroshiro and xoshiro in different variations.
×