Jump to content

Tommi Prami

Members
  • Content Count

    511
  • Joined

  • Last visited

  • Days Won

    6

Posts posted by Tommi Prami


  1. On 10/9/2023 at 7:43 PM, DelphiUdIT said:

    @Tommi Prami

    If you want commit the code in your repository and insert the test for the available of RDRAND and RDSEED, this is the code.
    Project Jedi has more info about that and of course the Intel documentation has all the documentation.
    I don't know about AMD, so i presume that AMD has the same two bits in use (hope).


    Tested in Win32 and Win64 Protected Mode, tested in virtual mode (WINXP - WIN11 32 bit and 64 bit), not tested in real address mode.
     

    
    interface
    
    //Explicity check if RDRAND and RDSEEK ara avilable
    //Global use
    
    TCheck_RDRAND_RDSEED = record
       tc_RDRAND: boolean;  //true if RDRAND is available
       tc_RDSEED: boolean;  //true if RDSEED is available
    end;
    
    var RDRAND_RDSEED_Available: TCheck_RDRAND_RDSEED;
    
    implementation
    
    const
      //ID string to identify CPU Vendor, the are a multitude .. but we focalize on this
      VendorIDxIntel: array [0..11] of AnsiChar = 'GenuineIntel';
      VendorIDxAMD: array [0..11] of AnsiChar = 'AuthenticAMD';
    
    //Internal functions, may be usefull to implement other check
    //Tested in Win32 and Win64 Protected Mode, tested in virtual mode (WINXP - WIN11 32 bit and 64 bit), not tested in real address mode
    //The Intel Documentation has more detail about CPUID
    //Jedi project has implemented TCPUInfo with more details.
    
    //First check that the CPU supports CPUID instructions. There are some exceptions with this rule,
    //but with very very old processors
    function Is_CPUID_Valid: boolean; register;
    asm
     {$IFDEF WIN64}
      pushfq                               //Save EFLAGS
      pushfq                               //Store EFLAGS
      xor qword [esp], $00200000           //Invert the ID bit in stored EFLAGS
      popfq                                //Load stored EFLAGS (with ID bit inverted)
      pushfq                               //Store EFLAGS again (ID bit may or may not be inverted)
      pop rax                              //eax = modified EFLAGS (ID bit may or may not be inverted)
      xor rax, qword [esp]                 //eax = whichever bits were changed
      popfq                                //Restore original EFLAGS
      and RAX, $00200000                   //eax = zero if ID bit can't be changed, else non-zero
      jz @quit
      mov RAX, $01                         //If the Result is boolean, the return parameter should be in A??? (true if A??? <> 0)
      @quit:
     {$ELSE}
      pushfd                               //Save EFLAGS
      pushfd                               //Store EFLAGS
      xor dword [esp], $00200000           //Invert the ID bit in stored EFLAGS
      popfd                                //Load stored EFLAGS (with ID bit inverted)
      pushfd                               //Store EFLAGS again (ID bit may or may not be inverted)
      pop eax                              //eax = modified EFLAGS (ID bit may or may not be inverted)
      xor eax,[esp]                        //eax = whichever bits were changed
      popfd                                //Restore original EFLAGS
      and eax, $00200000                   //eax = zero if ID bit can't be changed, else non-zero
      jz @quit
      mov EAX, $01                         //If the Result is boolean, the return parameter should be in AL (true if AL <> 0)
      @quit:
     {$ENDIF}
    end;
    
    //1) Check that the CPU is an INTEL CPU, we don't know nothing about other's
    //   We can presume the AMD modern processors have the same check of INTEL, but only for some instructions.
    //   No test were made to verify this (no AMD processor available)
    //
    //2) Catch the features of the CPU in use
    //
    //3) Catch the new features of the CPU in use
    //
    procedure CPUID_GeneralCall(InEAX: cardinal; InECX: cardinal; out Reg_EAX, Reg_EBX, Reg_ECX, Reg_EDX); stdcall;
    asm
     {$IFDEF WIN64}
      // save context
      PUSH RBX
      // CPUID
      MOV EAX, InEAX           //Generic function
      MOV ECX, InECX           //Generic sub function
      //
      //For CPU VENDOR STRING EAX := $0
      //ECX is not used when EAX = $0
      //
      //For CPU Extension EAX := $01
      //ECX is not used when EAX = $01
      //
      //For CPU New Extension EAX := $07
      //ECX should be $00 to read if RDSEED is available
      //
      CPUID
      // store results
      MOV R8, Reg_EAX
      MOV R9, Reg_EBX
      MOV R10, Reg_ECX
      MOV R11, Reg_EDX
      MOV Cardinal PTR [R8], EAX
      MOV Cardinal PTR [R9], EBX
      MOV Cardinal PTR [R10], ECX
      MOV Cardinal PTR [R11], EDX
      // restore context
      POP RBX
     {$ELSE}
      // save context
      PUSH    EDI
      PUSH    EBX
      // CPUID
      MOV EAX, InEAX           //Generic function
      MOV ECX, InECX           //Generic sub function
      //
      //For CPU VENDOR STRING EAX := $0
      //ECX is not used when EAX = $0
      //
      //For CPU Extension EAX := $01
      //ECX is not used when EAX = $01
      //
      //For CPU New Extension EAX := $07
      //ECX should be $00 to read if RDSEED is available
      //
      CPUID
      // store results
      MOV EDI, Reg_EAX
      MOV Cardinal PTR [EDI], EAX
      MOV EAX, Reg_EBX
      MOV EDI, Reg_ECX
      MOV Cardinal PTR [EAX], EBX
      MOV Cardinal PTR [EDI], ECX
      MOV EAX, Reg_EDX
      MOV Cardinal PTR [EAX], EDX
      // restore context
      POP EBX
      POP EDI
     {$ENDIF}
    end;
    
    //Function called from Initialization
    function CPUID_RDRAND_RDSEEK_Check: TCheck_RDRAND_RDSEED;
    var
      tempVendorId: array [0..11] of AnsiChar;
      HighValBase: Cardinal;
      HighValExt1: Cardinal;
      VersionInfo: Cardinal;
      AdditionalInfo: Cardinal;
      ExFeatures: Cardinal;
      StdFeatures: Cardinal;
      UnUsed1, UnUsed2: Cardinal;
      NewFeatures: Cardinal;
    begin
      Result.tc_RDRAND := false;
      Result.tc_RDSEED := false;
      //Check if CPUID istruction is valid testing the bit 21 of EFLAGS
      if Is_CPUID_Valid then
        begin
          //Get the Vendor string with EAX = 0 and ECX = 0
          CPUID_GeneralCall(0, 0, HighValBase, tempVendorID[0], tempVendorID[8], tempVendorID[4]);
          //Verifiy that we are on CPU that we support
          if (tempVendorId = VendorIDxIntel) OR (tempVendorId = VendorIDxAMD) then
            begin
              //Now check if RDRAND and RDSEED is supported inside the extended CPUID flags
              if HighValbase >=1 then  //Supports extensions
                begin
                  //With EAX = 1 AND ECX = 0 the Extension and the available of RDRAND can be read
                  CPUID_GeneralCall(1, 0, VersionInfo, AdditionalInfo, ExFeatures, StdFeatures);
                  //ExFeatures (ECX register) bit 30 is 1 if RDRAND is available
                  if (ExFeatures and ($1 shl 30)) <> 0 then
                    Result.tc_RDRAND := true;
                  if HighValBase >= 7 then
                    begin
                      //With EAX = 7 AND ECX = 0 the NEW Extension and the available of RDSEED can be read
                      CPUID_GeneralCall(7, 0, HighValExt1, NewFeatures, UnUsed1, UnUsed2);
                      //New Features (EBX register) bit 18 is 1 if RDSEED is available
                      if (NewFeatures and ($1 shl 18)) <> 0 then
                        Result.tc_RDSEED := true;
                    end;
                end;
            end;
        end;
    end;
    
    Initialization
      begin
        RDRAND_RDSEED_Available := CPUID_RDRAND_RDSEEK_Check;
      end;
    end.

    Bye

    Please make Pull request.

     

    -Tee-


  2. 16 minutes ago, Kas Ob. said:

     

    You already did, and it should work for x64 and only for X64, unless you are talking about the value checking and looping, in that case here a fix:

     

    What I can't understand how it worked on 32bit app, or at least it did not fail or die...

    Because I need 64bit random seed.

    So 32bit version should do some bit fiddling to make two calls and make 64bit value from two 32bit value?



    Something like:

     

    {$IF NOT Defined(WIN64)}
    function RDSEED64(const ARetryCount: UInt32 = 10): UInt64;
    var
      LValue1: UInt32;
      LValue2: UInt32;
    begin
      LValue1 := RDSEED32(ARetryCount);
      LValue2 := RDSEED32(ARetryCount);
    
      Result := UInt64(LValue1) shl 32 or LValue2;
    end;
    {$ENDIF}

    -Tee-


  3. I never really done anything with ASM, and it is more than less magic to me,  did ton of googling and landed this far... This seems to work, but I have no idea is it even remotely correct.

    function RDSEED64: UInt64;
    asm
      DB $48, $0F, $C7, $F8  // RDSEED 64bit value (if correct magic numbers)
      // The 64-bit result is already in RAX
    end;

    I think it would need as per Intel documentation some short, maybe constant loop, Apparently RDSEED returns 0 if it fails (Too many calls in short period of time). Also possibility checking the instruction availability would be nice.

    I've got even less idea how to port this to 64bit compiler.

    This is purely "academic" (Read hobby stuff) for me if seems too much work don't bother, but if someone really needs it and someone could help, I think there could be appreciation of some sorts.

     

    -Tee-


  4. image.png.b3150ca7ad57e6efeab025f5735f4ca6.png

    For some reason lot of units show on top of each other.

    Even if fixed, would be handy to have some hint, to give some info on the unit while hovering over, with maybe bigger font (Normal UI font), if zoomed to very small, then could check colored ones.... etc...

    Also this island at top left is bit strange.

    image.thumb.png.3493e8df4383ba7700a1224f83e1b2fa.png


  5. Very nice.

    Hope you continue to make it better.

    For one I would not need "relaxed search" from the Graph. Like type search 'settings custom'

    Would give me all units from the graph that would match those words. Like the Delphi Search for units... (Ctrl + F12).

    You can put everything you just remember the unit you are looking for. Because there is huge number of unis in big projects, and finding from the Graph (without filtering)

     

    just my 0.02€...

     

    Very good. Thanks.

     

    -Tee-


  6. Yellow,

     

    Stumbled upon these:
    https://github.com/YWtheGod/ZSTD4Delphi

    https://github.com/DenisAnisimov/ZSTD.pas

    No idea will they work and so, if someone has need and/or interest, here you are...

     

    -Tee-

    Benchmarks

    For reference, several fast compression algorithms were tested and compared on a server running Arch Linux (Linux version 5.5.11-arch1-1), with a Core i9-9900K CPU @ 5.0GHz, using lzbench, an open-source in-memory benchmark by @inikep compiled with gcc 9.3.0, on the Silesia compression corpus.

    Compressor name Ratio Compression Decompress.
    zstd 1.4.5 -1 2.884 500 MB/s 1660 MB/s
    zlib 1.2.11 -1 2.743 90 MB/s 400 MB/s
    brotli 1.0.7 -0 2.703 400 MB/s 450 MB/s
    zstd 1.4.5 --fast=1 2.434 570 MB/s 2200 MB/s
    zstd 1.4.5 --fast=3 2.312 640 MB/s 2300 MB/s
    quicklz 1.5.0 -1 2.238 560 MB/s 710 MB/s
    zstd 1.4.5 --fast=5 2.178 700 MB/s 2420 MB/s
    lzo1x 2.10 -1 2.106 690 MB/s 820 MB/s
    lz4 1.9.2 2.101 740 MB/s 4530 MB/s
    lzf 3.6 -1 2.077 410 MB/s 860 MB/s
    snappy 1.1.8 2.073 560 MB/s 1790 MB/s

     


  7. Was just thinking,

     

    Can anyone figure out why Embarcadero could/would/should not publish rtl, compiler etc versions and codename for the beta, just as they include first outsider to the beta test?
     

    Those things are not that big of an secret. or allow publishing trivial work done with beta versions. Like the packages or support for IDE plugins (with some limitations maybe??).

     

    -Tee-


  8. I get the points raised.

    But if you are in not under NDA, making a guess what defines you might need to tweak into .inc file or put into the package, can't violate the NDA. 

    If you are under NDA and just publish packages and/or project files etc, Emba would shoot them self to the foot if they would enforce it in that case, IMHO. But seen stupider things done, so never know 😄

    Problem of the NDA is, I assume, that you can't even ask for help, from  lets say, how to add D12 support for the Jcl. But I might be cunning and ask how did you make support for the D11,x And try to duplicate the process.

     

    And this is kind of funny, because everyone knows few people that has D12 beta, and are under NDA most likely. And Embarcadero it self leaks that information. But person can't say anything and has to dance around. I understand that there must be some kind of limitations under beta, but making things too tight sure puts everyone in beta in  position that they have to do more work that they should. Also most likely can't test everything that they would like to, But this is just pointless rambling because it will not affect the company policy for sure...

    -Tee-

     

     

    • Like 1

  9. Yellow,

     

    Now that there is "Public" Beta of Delphi 12. ( https://blogs.embarcadero.com/delphi-supports-android-api-33-via-yukon-beta/ )

    Some OSS component/library supporters have already made "Educated guess" what there need to be done to support D12, making packages and so.


    If possible/time/willing to make such a guess, please do, I think it would make everyone's job easier to test the Beta, since almost all of products made with Delphi, use some kind of Open source libs. I think it would just help all people in beta, even if maintainer would not be. In some cases making packages are trivial thing, but quite waste of time if everyone in Beta will do it themselves.

     

    Like the great folks maintaining: 


    (Just to mention two I've noticed)

     

    -Tee-


  10. Ah,

     

    And forgot that this forum won't let me edit after some time period. Never understood why. Maybe someone at past has been D**K HEAD abusing the edit functionality.  Would be better to kick those out, than not been able to correct typos and mistakes, or give more info to the initial message, if problem has been solved. But I digress..

    • Like 1

  11. Code that builds in one project fails in other.
     

      TResamplerObj = class
        id: integer;
        name: string;
        func: TResamplerFunction;
      end;


    if I and public-keyword after class() it'll build
     

      TResamplerObj = class
      public
        id: integer;
        name: string;
        func: TResamplerFunction;
      end;

    I've never seen behaviour like this.

    First of all usually there is strict private/private keyword. But the code should build, because it'll do so in other projects.

     

    -Tee-


  12.  

    Compiler supports only the short versions of compiler direcctives in the IFOPT

    {$IFOPT C+}
      LTempVariable :=
    {$ENDIF}
      DoSometingThatReturnsSomething:
      Assert(LTempVariable > 0, 'Should return greater than Zero');

    would be way easier to read and understand what is going on with long version

    {$IFOPT ASSERTIONS ON}
     LTempVariable :=
    {$ENDIF}

     

    https://quality.embarcadero.com/browse/RSP-42105

     

    I really do not like those shortened version of Compiler directives. Would need to use them a lot, if at least I would remember them.

    • Like 2

  13. Yellow,

     

    Watched this video last night and it had interesting things:  

     

    I

    image.thumb.png.6bdd26d891d7ed6cc58cf3215120d8da.png

     

    Did not test this yet in any way in Delphi, how to write it to make it behave same way as the C++, but this trick gave quite a performance boost.

     

    Also I've not  never looked into the "perfect hash tables" and there was quite interesting tricks there, especially when you have and suitable dataset to use it for. 

     

    -Tee-

×