Jump to content

Stefan Glienke

Members
  • Content Count

    1370
  • Joined

  • Last visited

  • Days Won

    130

Posts posted by Stefan Glienke


  1. On 1/25/2019 at 6:35 PM, Erik@Grijjy said:

    You mean by moving those checks to a separate method?

    No. I don't know about the ARM codegen but on windows if you do the pattern:

     

    if out of range then

      raise exception;

    do stuff;

     

    This always generates a jump above the raise to get to do stuff for the common case of "in range".

    When you write:

     

    if in range then

      do stuff

    else

      raise exception;

     

    In this case you don't have a jump for the common case of being in range. Depending on how you structure the code you then have two returns in each branch of the if so no jump inside the method.

    If you like to inline this method it is also a good thing to put the raise exception into its own subroutine to not bloat the inlined code.

      


  2. What's also interesting about Length and High is that if you are just writing code that directly compiles into a binary they are being inlined by the compiler whereas if you are using them in units that are pre-compiled as part of a package (if you are 3rd party component vendor for example) they are not and always cause a call to System._DynArrayHigh and System._DynArrayLength. Funny enough this is not the case for the source shipped with Delphi because their DCUs are not generated from their containing packages.

    • Thanks 2

  3. I don't see the Delphi compiler performing any control flow analysis and eliminate code in any possible future.

    C++ might do that though (see https://stackoverflow.com/questions/6664471/observable-behaviour-and-compiler-freedom-to-eliminate-transform-pieces-c-co)

     

    However I requested adding a way to specifically force linking of types into the binary some while ago - see https://quality.embarcadero.com/browse/RSP-18389

    • Like 1

  4. On 1/19/2019 at 2:06 AM, Schokohase said:

    You will find a Delphi implementation at Spring4D

    Thanks for pointing that out - in the currently released version the type still has a T in its name and is in the unit Spring.Designpatterns (the move and renaming happens in the upcoming 1.3 version which is not yet released).

    Also in both versions the explicit hardcasting of the anonymous method is not required - there is an implicit operator for that.

     

    Also FWIW I usually put specifications that are used in several places as static functions into their own type or helper just like this (you can also make them standalone routines if you dislike the redundant typing of TProjectFilters):

     

    type
      TProjectFilters = record
        class function IsActive: TSpecification<TProject>; static;
        class function WorkhoursGreaterThan(const value: Integer): TSpecification<TProject>; static;
      end;
    
    class function TProjectFilters.IsActive: TSpecification<TProject>;
    begin
      Result :=
        function(const p: TProject): Boolean
        begin
          Result := p.Active;
        end;
    end;
    
    class function TProjectFilters.WorkhoursGreaterThan(
      const value: Integer): TSpecification<TProject>;
    begin
      Result :=
        function(const p: TProject): Boolean
        begin
          Result := p.Workhours > value;
        end;
    end;
    
    var
      spec: TSpecification<TProject>;
    begin
      spec := TProjectFilters.IsActive and TProjectFilters.WorkhoursGreaterThan(50);

    Also what others already pointed out: lets look at for example CountActiveProjects and ListActiveProjects - what do they have in common? They do something on the active projects - so break that down into getting the active projects and what is done on them. If you want to keep TArray<TProject> and alike you probably have to write the filtering yourself. I just point out how easy it will be using IList<T> from Spring.Collections:

     

    procedure PrintProject(const p: TProject);
    begin
      //...
    end;
    
    var
      projects: IList<TProject>;
      activeProjects: IEnumerable<TProject>;
    begin
      activeProjects  := projects.Where(
        function(const p: TProject): Boolean
        begin
          Result := p.Active;
        end);
      Writeln(activeProjects.Count);
      activeProjects.ForEach(PrintProject);

    You can even turn a TArray into an IEnumerable where you can apply filtering and stuff (yes, some minor overhead - measure yourself if it's worth it to keep your code compact and with less explicit loops);

     

    var
      projects: TArray<TProject>;
      activeProjects: IEnumerable<TProject>;
    begin
      activeProjects  := TEnumerable.From(projects).Where(
        function(const p: TProject): Boolean
        begin
          Result := p.Active;
        end);
      Writeln(activeProjects.Count);
      activeProjects.ForEach(PrintProject);

     


  5. Quote
    • For Delphi, no visible effect - this is not something that is normally dug into by developers. If you have assembly code for Win64, you may want to check its handling of parameters between 4 and 8 bytes.

    Well, not quite - it's not a common case but I want to point that out:

    If you have any existing 64bit DLL that you compiled with a previous version and are now calling from a 10.3 compiled binary or vice versa that has any of the affected record types you are in trouble. You need to compile both with the same version.

     

    Also if I am not mistaken it is between 5 and 8 bytes, 4 bytes fit into a register on both and should not be affected.


  6. 1 hour ago, Primož Gabrijelčič said:

    Was IDE Fix Pack merged into 10.3 release?

    Has nothing to do with that - I suspect that the dproj was migrated from a version before 10.3 where someone tested with those options. Since there is no IDEFixPack for 10.3 yet, these options will have no effect.

    • Like 1

  7. My point was that countering that there is "uncontrollable behavior" sometimes with showing that there is nothing wrong when firing off a bunch of sleep threads is useless. A thread that does nothing but sleep suspends and gives control back to the OS scheduler which knows not to wake up that thread until time is over. You can see that in the numbers you posted.

     

    Also when doing IO heavy stuff you hardly want to put that into CPU threads but use I/O completion ports.


  8. Second alternative possibly does an unnecessary instruction but the first has a jump in both cases - so it depends.

    If you are micro-optimizing code (which you usually don't) you might want to keep the common path jump free.


  9. 6 minutes ago, Attila Kovacs said:

    Can't reproduce.

    I add Generics.Collections to some uses, then ctrl+click on it, boom

     

    image.png.b6efcddf19a08198b57fe6b39721bdc0.png

     

    Anyhow this is not the issue here as Uwe said, even 500 million failed createfiles are not burning a CPU core but rather the HDD/SSD.

    How you can see what is burning your CPU was explained in the other thread.


  10. 4 minutes ago, Attila Kovacs said:

    I understand but please tell me how can I get a page full of "name not found" in procmon?

    I've it running, what should I do?

    Create a new vcl application. Add any third party unit (one that is not immediately found in the first entry in the library path) - thus not a Delphi RTL/VCL/... unit or a Delphi unit without its fully qualified name. Then compile. The more entries you have in the library path and the more entries in the project options in unit scope names the more entries will pop up in procmon because it tries every possible combination (I don't remember in which order)


  11. 8 minutes ago, Attila Kovacs said:

    Maybe I need glasses

    Probably - as far as I can see on saturday Stéphane wrote about the fresh install and referred to the wrong registry key being accessed. Yesterday he wrote about a fresh VM installation - at that point he did not claim that Rio was not installed without third party components. And if you look into the file he talked about earlier in this thread you can see that it uses quite a lot of third party stuff (like TMS Aurelius).


  12. @Stéphane Wierzbicki @Attila Kovacs You should learn what procmon is telling there - all these attempted createfile are results of checking if the file exists and all the directories are obviously directories in the library path as a result of installing several third party components. And due to the way Delphi handles library/search paths when compiling (iterating them looking for the requested file and trying them with any possible unit scope - that is why you see it trying Vcl.Shell.blabla there, because usually Vcl.Shell is one of the unit scopes being put into a VCL project) this is what you get - nothing unusual there.


  13. 3 hours ago, Clément said:

    Is it even possible to improve the compiler as much?

    Yes, you can improve the compiler (the language) as much as that it is partially safe to access raw memory without copying it - google for: .NET Span<T>

    I did some experiments with it in Delphi and it improved some string parsing code that did not have to allocate new strings but also did not have to work with raw and rather unsafe PChar.

    See https://bitbucket.org/snippets/sglienke/7e6xoe/span - this however cannot do what the C# compiler can do with ref (ensure that it only lives on the stack to not lives longer than what it refers to and these things) plus C# has readonly ref - basically a readonly pointer.

    • Like 1
×