Jump to content

Stefan Glienke

Members
  • Content Count

    1365
  • Joined

  • Last visited

  • Days Won

    130

Everything posted by Stefan Glienke

  1. Stefan Glienke

    MAP2PDB - Profiling with VTune

    All I can say is that it did not work properly for me - when clicking on the method I mentioned above it wanted to open Spring.pas and marked an obviously completely wrong line.
  2. Stefan Glienke

    MAP2PDB - Profiling with VTune

    Very nice! - Just a thing about the map file parsing - and actually that's an issue that I've seen with most map file analyzing tools as they do it wrong - relating symbols from generics to the correct type and unit - example: Spring.{System.Generics.Collections}TDictionary<System.Pointer,System.Classes.TList>.GetBucketIndex This means the code for this method because its a generic was compiled into the Spring.dcu because I used that TDictionary from the RTL in Spring.pas - but the source will not be found there but in the unit in the curly brackets: System.Generics.Collections
  3. Stefan Glienke

    Introducing Delphi Uses Helper

    I explained that in the article. DelphiAST is being used to index using the defines of a Win32 application.
  4. But before it did not run in an endless loop like the code from @pyscripter does šŸ¤·ā€ā™‚ļø
  5. Stefan Glienke

    List of usable RegEx for source code

    No - when the already allocated block is large enough it doesn't do much. And when it has to actually allocate it just does a lock cmpxchg on a bool field of the block types - when its already locked by another thread it simply tries the next bigger one. Speaking of FastMM4 allocation was never the problem with many threads because of this mechanism - it could only lead to a bit memory overhead because some small blocks might be little overallocated because it had to go past the currently locked sub allocators. The issue was in deallocating because that needs of course to the allocator it the memory belongs to. This is what Pierre addressed in V5. FastMM having *a* global lock is a myth.
  6. That does not work at all - CharNext does not work well. And that article is from 2007 - did we even have emojis back then? šŸ˜„ Try yourself with the testcase here: https://docs.microsoft.com/en-us/dotnet/core/compatibility/globalization/5.0/uax29-compliant-grapheme-enumeration
  7. Stefan Glienke

    Delphi WAT of the day

    function (const arr: TArray<T>): RecWithTwoFields (Pointer, Integer) Bonus: inlining that function looks like this - go go eax, you got it eventually!
  8. Stefan Glienke

    Delphi WAT of the day

    Which is not what the documentation says:
  9. Stefan Glienke

    Delphi WAT of the day

    Inspired by RSP-28311: {$APPTYPE CONSOLE} uses TypInfo; type generic = record class procedure test<T>(const value : T); static; end; class procedure generic.test<T>(const value: T); begin Writeln(GetTypeName(TypeInfo(T))); end; procedure test(a: Int32); overload; begin Writeln('Int32'); end; procedure test(a: Int64); overload; begin Writeln('Int64'); end; procedure test(a, b: Int32); overload; begin Writeln('Int32'); end; procedure test(a, b: Int64); overload; begin Writeln('Int64'); end; const one = Int64(1); two = Int64(MaxInt); three = Int64(MaxInt)+1; four: Int64 = 1; begin generic.test(one); // Int64 generic.test(two); // Int64 generic.test(three); // Int64 generic.test(four); // Int64 test(one); // Int64 test(two); // Int64 test(three); // Int64 test(four); // Int64 test(one, 1); // Int32 ?! test(two, 1); // Int32 test(three, 1); // Int64 test(four, 1); // Int64 test(one, Int64(1)); // Int64 test(Int64(1), 1); // Int32 ?! end.
  10. In 1. you write that you don't have much time. Do you think that 2. or 3. would require less time?
  11. I know how to write a debugger visualizer and how to use the IOTADebuggerVisualizerValueReplacer. What I want to achieve is creating sub nodes with values like you get when you have a dynamic array, a record or an object. However the mentioned interface only provides a method to produce a string which is printed but no way to produce some kind of sub structure. I also know about IOTADebuggerVisualizerExternalViewer as being used for TStrings where you can click on the magnifier icon to open up another window but that is not what I would like to have. I am looking for a way to dynamically create sub entries for some type which seems to be beyond the capabilities of the ToolsAPI. But we have some people that know a bit about the internals of the IDE any maybe someone is able to find a way to achieve this. To illustrate this. uses System.Generics.Collections, Spring.Collections; procedure Main; var arr: TArray<Integer>; listA: TList<Integer>; listB: IList<Integer>; begin arr := [1, 2, 3]; listA := TList<Integer>.Create; listA.AddRange(arr); listB := TCollections.CreateList<Integer>(arr); end; I get this in the local variables view (this is from 10.4.2 where visualizers for TList<T> and alike were added): When the debugger sees a dynamic array type it shows the elements as sub nodes - thus you can "cheat" the watches: So what I would like to see is the expand icon on my listB and then the elements in the list in sub nodes just like in dynamic array.
  12. Stefan Glienke

    Delphi WAT of the day

    Exactly - at runtime. Warning would be nice, don't you think? Edit: to be clear not because I put the -1 there which will for sure blow up but because Integer->Cardinal will blow up for 50% of the value range. We have W1023 and W1024 when comparing or combining, but assignment/parameter passing blows up at runtime... eventually, some day.
  13. Stefan Glienke

    Delphi WAT of the day

    Inspired by that other thread: procedure TypeSafeMyAss(i: Cardinal); begin end; var i: Integer; begin i := -1; {$RANGECHECKS ON} TypeSafeMyAss(i); end.
  14. The demand is being able to compile the existing framework šŸ˜‰
  15. DUnit is not actively being maintained, true. But I am planning to keep on using it - it achieved a nice balance between being flexible enough but at the same time very simple and not overengineered, ymmv. I don't care what some guy in that issue says - they have been doing modifications to DUnit themselfes for ages and suddenly its a DUnit issue they cannot/don't want to fix? How ridiculous tbh. I have my opinion about DUnitX - but it's certainly not deprecated but Vincent does not care for adding C++ support afaik. I was in fact looking into dusting off DUnit, removing old cruft like the CLR stuff and applying some optimizations such as making parameters const, reducing unnecessary overhead in Check methods and so on (doing so improves the overall runtime of my tests by like 10% simply because the CheckSomething methods are faster!) while doing that I could look into making it work with C++
  16. Out of interest - and possibly even making sure that TestInsight works with C++ using DUnit (no promise though) - what does not work with DUnit in C++?
  17. Stefan Glienke

    Range Check Error ERangeError

    What exactly is strange about it? They changed WPARAM from INT_PTR to UINT_PTR in XE2. The point is that the hint still does not show the actual alias name being used in the declaration of the routine but the actual type it aliases. And that is wrong because that causes these kinds of defects when the alias changes because people of course did a cast to the type being shown in code insight.
  18. Stefan Glienke

    Range Check Error ERangeError

    Don't blame the developer - blame the poor hints - taken from Delphi XE and 10.4: Before anyone tells me to report it - been there, done it! https://quality.embarcadero.com/browse/RSP-17110 The cast to Integer is indeed wrong - see the assembly code with Bounds checking enabled: Unit2.pas.31: PostMessage(Handle, CM_SEARCH, Integer(Sender), Key); 0060F70F 8B45F4 mov eax,[ebp-$0c] 0060F712 0FB700 movzx eax,[eax] 0060F715 50 push eax 0060F716 8B45F8 mov eax,[ebp-$08] 0060F719 85C0 test eax,eax 0060F71B 7905 jns $0060f722 0060F71D E80686DFFF call @BoundErr 0060F722 50 push eax 0060F723 6800CA9A3B push $3b9aca00 0060F728 8B45FC mov eax,[ebp-$04] 0060F72B E8406EF4FF call TWinControl.GetHandle 0060F730 50 push eax 0060F731 E82A67E0FF call PostMessage With cast to WPARAM: Unit2.pas.31: PostMessage(Handle, CM_SEARCH, WPARAM(Sender), Key); 0060F70F 8B45F4 mov eax,[ebp-$0c] 0060F712 0FB700 movzx eax,[eax] 0060F715 50 push eax 0060F716 8B45F8 mov eax,[ebp-$08] 0060F719 50 push eax 0060F71A 6800CA9A3B push $3b9aca00 0060F71F 8B45FC mov eax,[ebp-$04] 0060F722 E8496EF4FF call TWinControl.GetHandle 0060F727 50 push eax 0060F728 E83367E0FF call PostMessage To reproduce try enabling top down memory allocation in your windows which will cause the Sender pointer to be large enough that it will be negative when cast to Integer
  19. Stefan Glienke

    QueryPerformanceCounter precision

    Google benchmark also uses GetProcessTimes - here is an article about the differences. And there you can also see why benchmark does a certain number of iterations on the profiled code to ensure a certain overall duration (the number of iterations dynamically depends on the single duration of the measured code) - as you can also see in the presentation from Chandler I linked earlier Another consideration with all these methods is once you benchmark multithreaded code the wall time might not be the information you want.
  20. Stefan Glienke

    First line of Code Insight not selected (10.4.2)

    I tried this on two different installations with all kinds of different options set for CodeInsight and it always works. Both were on Windows 10 though so it could be an OS thing or interfering with some other third party plugins (I remember cnPack interfering with CodeInsight before)
  21. Stefan Glienke

    QueryPerformanceCounter precision

    For microbenchmarking you don't need that high of a precision - you simply run the benchmarked function thousands of times and then divide by the number of runs and you got your duration. Watch some videos by Chandler Carruth like these two:
  22. Then how about you describe what you are trying to achieve?
  23. Yes but beware this will be very nasty - thanks to poor type inference in Delphi. You have to use the GroupBy overload with 4 generic parameters: type TGroup = record AppName: string; Groups: IEnumerable<IGrouping<string,TVariable>>; end; var GroupedTwoLevels: IEnumerable<TGroup>; begin GroupedTwoLevels := TEnumerable.GroupBy<TVariable, string, TVariable, TGroup>(IEnumTV, function (const v: TVariable): string begin Result := v.AppName; end, function (const v: TVariable): TVariable begin Result := v; end, function (const key: string; const vars: IEnumerable<TVariable>): TGroup begin Result.AppName := key; Result.Groups := TEnumerable.GroupBy<TVariable, string>(vars, function(const v: TVariable): string begin Result := v.PrjName; end); end); ListBox5.Clear; for var g1 in GroupedTwoLevels do begin ListBox5.Items.Add(g1.AppName); for var g2 in g1.Groups do begin ListBox5.Items.Add(' ' + g2.Key); for var v in g2 do ListBox5.Items.Add(' ' + v.AppName + '_' + v.PrjName); end; end;
  24. The culprit here is a different one: in 1.2.4 Shuffled caused a shuffle of the input sequence when being called while 2.0 does it every time when the enumerator is being used (internally or externally) ElementAt for example does it - that means during your loop to print items to ListBox2 they are reshuffled every time and then the nth element is being picked by MoveNext n times. And then again the shuffle is triggerd one time for the iteration being done by GroupBy. This follows the implementation in MoreLinq where this was taken from originally. If you want to shuffle but reuse the order then either do TCollections.CreateList(source.Shuffled) or TCollections.CreateList and then call Shuffle on that list. Also I advice against using index based loops and ElementAt on IEnumerable - this will be O(nĀ²) as many sequences are lazy evaluated and cause enumeration every time you call ElementAt. When you fix this you will notice the output of GroupBy between 1.2.4 and 2.0 is exactly the same -> ordered by the appearance of the items in the source.
  25. Dynamically allocating records and then not storing them as reference won't work because you just create memory to then do a value copy once you add the item to the list making the dynamically allocated memory useless. I suggest you read up on the difference between value and reference types - I am sure there is a chapter about that in Object Pascal Handbook by Marco Cantu which should be available for free to you as owner of Delphi 10.4
Ɨ