Jump to content

Stefan Glienke

Members
  • Content Count

    1518
  • Joined

  • Last visited

  • Days Won

    154

Everything posted by Stefan Glienke

  1. Somehow I cannot believe that ZEOS did not properly support 64bit until now - you must have been using some old code
  2. Stefan Glienke

    TParallelArray Sort Performance...

    Quicksort with comparer calls compiled by a mediocre compiler operates far below L3 cache speed.
  3. Stefan Glienke

    Records as TDictionary keys

    Of course - TDictionary<K,V> is hashtable based, so it needs GetHashCode and Equals
  4. There should not be any temp, nor assign call tbh. Check out this code: {$APPTYPE CONSOLE} uses SysUtils; type TMyRec = record x: Integer; class operator Initialize(out dest: TMyRec); class operator Finalize(var dest: TMyRec); class operator Assign(var left: TMyRec; const[ref] right: TMyRec); end; function MyDefault: TMyRec; begin Writeln('default - ', IntToHex(IntPtr(@Result))); Result.x := 0; end; class operator TMyRec.Initialize(out dest: TMyRec); begin Writeln('init - ', IntToHex(IntPtr(@dest))); end; class operator TMyRec.Finalize(var dest: TMyRec); begin Writeln('finalize - ', IntToHex(IntPtr(@dest))); end; class operator TMyRec.Assign(var left: TMyRec; const[ref] right: TMyRec); begin Writeln('assign'); end; procedure Main; var r: TMyRec; begin r := MyDefault; end; begin Main; end. Now we can argue why there is no assign call because we are assigning the result of the MyDefault function to r. But even though we have declared an assign operator it does what it always does with managed return type - passing it as hidden var parameter. I said this before and I say it again - CMR are broken as designed and personally I stay the heck away from them. I remember some years ago there was a question on SO about struct default ctors serving as default initializers and why C# does not have them and I don't remember if it was Jon or Eric explained that it would cause all kinds of trouble. Edit: Ah, here it is: https://stackoverflow.com/a/333840/587106 - eventually they added them in C# 10 but there is quite some extensive language spec - when I asked for the CMR spec it was all crickets. FWIW the Delphi implementation suffers from exactly the situation that Jon describes - allocate a dynamic array of some CMR and watch all the initializers run. Which is completely bonkers - C# 10 does not do any of that for array allocation - see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/parameterless-struct-constructors#array-allocation
  5. Stefan Glienke

    MAP2PDB - Profiling with VTune

    you can generate a dpk with the help of System.SysUtils.GetPackageInfo
  6. Stefan Glienke

    MAP2PDB - Profiling with VTune

    Recompile the RTL yourself using source\rtl\buildrtl.bat and generate map file - that's how I used to do it until Anders added jdbg support.
  7. Stefan Glienke

    Recursive anonymous functions

    There is no local variable - on the source code level, yes there is, but implementation wise they live inside the heap memory of the compiler generated instance. That's why captured variables never appeared in the local variables view until recently when the kinda implemented support for it.
  8. Stefan Glienke

    Watch me coding in Delphi on YouTube

    omg, no! Followed by "How do I fix these random Access Violations that appear in my code"
  9. Stefan Glienke

    Recursive anonymous functions

    To understand this, you need to understand how anonymous methods are implemented. The compiler implements them by creating a class that inherits from TInterfacedObject. The anonymous method type is a special interface with one method called Invoke, which has the signature of the anonymous method type. When you add ReportMemoryLeaksOnShutdown := True to the code above you will see that it reports one instance of a class called MakeFib$ActRec - that is the class name of the compiler-generated class for the anonymous method. The class also contains fields for every captured variable - in this case the local variable fib is being captured with holds the reference to itself so this is the circular interface reference that causes the memory leak. To demonstrate here is the code as the compiler implements it: type MakeFibAnonClass = class(TInterfacedObject, TFunc<integer,int64>) fib: TFunc<integer,int64>; function Invoke(value: integer): int64; end; function MakeFibAnonClass.Invoke(value: integer): int64; begin if value < 3 then Result := 1 else Result := fib(value - 1) + fib(value -2); end; function MakeFib_Impl: TFunc<integer,int64>; var obj: MakeFibAnonClass; begin obj := MakeFibAnonClass.Create; obj.fib := obj; Result := obj.fib; end;
  10. Convert<T> from TValueHelper in Spring. See https://bitbucket.org/sglienke/spring4d/src/2.0.1/Source/Base/Spring.pas#lines-651
  11. Stefan Glienke

    GExperts for Delphi 10.4.1

    get the source from SourceForge open Projects\DelphiXx120\GExpertsRS120.dproj compile run Binaries\Register-GExperts-XX120.cmd restart IDE
  12. Stefan Glienke

    updated Delphi64RTL intel ipp onetbb

    You *must not* remove that line - Move in Delphi allowed to be called with negative Count (a possible result of some size calculation), resulting in a no-op in the System implementation. Passing a negative number to most C++ implementations will result in passing a value >2mio because their size parameter is unsigned. Also, the performance difference is hardly about that little check but the ippsMove_8u implementation.
  13. Stefan Glienke

    updated Delphi64RTL intel ipp onetbb

    ippMove is not much faster than System.Move in Delphi 12. In fact, it performs noticeably worse on small sizes (below 1k) and for some reason completely falls off the cliff on sizes that are >20k running 2-4 times slower.
  14. Only on 64bit though - on 32bit the size of TDynArrayRec is 8 byte, if the memory manager getmem returns 16byte aligned memory that makes the elem[0] 8byte aligned. This is why i said that the RTL has to take care of it - the same is the case for strings. Relying only on the memory manager which is replaceable prevents the RTL from doing things that it could if certain data would have certain alignments. Using SSE for some string handling functions and such.
  15. That would be true if dynamic array allocation would be done in a way that ensures that element [0] would be at a 16 byte aligned address, which is not the case
  16. Not exactly, it moves everything in the array to the front and then calls SetLength with the new length. What that does internally depends on the refcount of the array. If it's 1, then it does a Realloc (shrinking in place, though depends on the memory manager what exactly happens, typically for a small downsize it does it in place, thus basically resulting in a no op) If it's greater than 1 it allocates a new block and copies the content over - I would say calling SetLength inside of Delete is a bug because everything was already moved in place thus the behavior of SetLength is not to be desired in this case. In fact this leads to some corrupted copy lying around Reported https://embt.atlassian.net/servicedesk/customer/portal/1/RSS-1532 Edit: apparently this is already known since 2020 - https://quality.embarcadero.com/browse/RSP-27870
  17. Stefan Glienke

    Devin AI - Is it already happening?

    Because things like Clean room design exist to minimize the chances of any copyright infringement. There have been lawsuits over "similarly enough looking" code in the past. Also, the simple fact that gen AI does not care about any license attribution which you would have to follow if you take any source code with one of the major permissive licenses that still require attribution.
  18. Stefan Glienke

    Devin AI - Is it already happening?

    It's really embarrassing to see how many people who work in software development don't know how generative AI works and are being fooled by it like an average TikTok teenager.
  19. Stefan Glienke

    Devin AI - Is it already happening?

  20. Stefan Glienke

    Remove uses with interface

    This and also a kind of limited approach given that the lifetime of all those UI elements is bound to the application lifetime and they are all singletons (meaning that you cannot have more than one instance of say ITestDlg)
  21. Stefan Glienke

    Devin AI - Is it already happening?

    The last thing I know of is that Devin AI was fake (that info is from April 2024 when the entire developer community was all over the demo they showcased). Do you know more?
  22. Stefan Glienke

    how to filter on source files using VTune?

    Changing anything with the map file will only remove the names, the functions being called will still be in the sampling result because VTune is a sampling profiler. Given that obviously, your performance problem was not with these functions they should not be a significant part of the result percentage-wise - if they are, they are part of the issue.
  23. Can't be asked - I am using the sfw (safe for work) version 😇
  24. FWIW the assembly implementation of that function is pointless given you can do it in a way more readable way - also performance cannot be a reason given the following call to mem_write causes a temporary heap allocation to convert your hex_code variable into an AnsiString. Quickly slapped together (anyone who wants to further optimize this - be my guest, i cba right now): type hex_code = Array [1 .. 4] of AnsiChar; function Int2Hex(c: Word): hex_code; const HexChars: array[0..15] of AnsiChar = '0123456789ABCDEF'; var i: NativeUInt; begin i := c; Result[4] := HexChars[i and $0F]; i := i shr 4; Result[3] := HexChars[i and $0F]; i := i shr 4; Result[2] := HexChars[i and $0F]; i := i shr 4; Result[1] := HexChars[i and $0F]; end; and then instead of mem_write with AnsiString as the first argument use one that writes 4 bytes at once.
×