Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 07/22/25 in all areas

  1. Anders Melander

    Calling routines overhead

    Profile it. The significance of the overhead really depends on what the routine is doing and how often it is called. For example if the call overhead is X but the routine itself takes 1000*X to execute then the overhead is insignificant. Apart from the overhead of the call itself there's the overhead of passing parameters. You need to learn how parameters are passed in order to optimize them. Not all parameter types can be passed in registers, Delphi doesn't use all available registers, 32-bit and 64-bit does things differently, etc. Also be aware that if you pass literal floating point numbers as parameters, the compiler might not consider the literal values to be the same type as the parameter which means that it will produce code to convert the values to the correct type. For example, if the parameter type is Single and you need to pass 0.5, then pass it as Single(0.5) - or declare a typed constant with the value and pass that. Set Code Inlining Control=Auto to have the compiler automatically inline small routines. With regard to writing stuff in assembler be aware that assembler routines can't be inlined so the call overhead becomes mandatory. For example, in my code one constant bottleneck is calls to Round and Trunc. I have assembler versions of these two functions which are much faster but unfortunately the call overhead completely eliminate the performance gain so they are basically useless. It's beyond me why Delphi doesn't implement these two as intrinsics. They are listed as such but they are implemented as regular functions. Not only that, but the Pascal version will provide a reference implementation to test and benchmark against and it will help documenting what the assembler versions does.
  2. Kas Ob.

    LoadLibrary and FreeLibrary notification

    Yes, it might be be slower, but the idea is even with your cache you will have to walk it, and if you re-refactored my code above it is really just loop over linked-list, In case you want to test it, then notice that PEB is immovable like its LdrData, so that part can be in initialization clause, this will leave the code close to function FindModuleByAddress(Address: Pointer): TModuleInfo; var ModuleEntry: PLDR_DATA_TABLE_ENTRY; CurrentEntry, FirstEntry: PLIST_ENTRY; ModuleBaseAddr, ModuleEndAddr: NativeUInt; FlinkPtr: PPointer; ProtCounter: Integer; // protection counter against looping over ring doubly linked list begin Result.IsValid := False; FlinkPtr := PPointer(NativeUInt(LdrData) + Flink_OFFSET); // Offset is 12 for 32bit and 24 for 64bit CurrentEntry := FlinkPtr^; if AddressViolateMemoryRange(CurrentEntry) then Exit; FirstEntry := CurrentEntry; // protection against endless looping over ring list ProtCounter := 0; // protection against endless looping over ring list in case FirstEntry is unloaded after the fact while Assigned(CurrentEntry) and (not AddressViolateMemoryRange(CurrentEntry)) and (CurrentEntry <> PList_Entry(NativeUInt(LdrData) + Flink_OFFSET)) do begin ModuleEntry := PLDR_DATA_TABLE_ENTRY(CurrentEntry); try if Assigned(ModuleEntry^.DllBase) then begin ModuleBaseAddr := NativeUInt(ModuleEntry^.DllBase); ModuleEndAddr := ModuleBaseAddr + ModuleEntry^.SizeOfImage; if (NativeUInt(Address) >= ModuleBaseAddr) and (NativeUInt(Address) < ModuleEndAddr) then begin // found module that have the address .. Result.IsValid := True; Exit; end; end; except // Ignore access violations, do not handle anything here end; if ProtCounter >= LOOPING_PROTECTION_LIMIT then Exit; Inc(ProtCounter); CurrentEntry := CurrentEntry^.Flink; if CurrentEntry = FirstEntry then Break; end; end; As for caching, i think you are the best one to decide if you want to cache few (may be 3 and that it) modules addresses that will be %90 of the times in any stack call, the EXE module itself and kernel and User32, saving these 3 will make the protection counter way better than random 1000, by comparing against loaded EXE address and trigger exit after second occurrence, this will prevent loop up to 1000. In all cases, you are welcome.
  3. You can use WINMD or better this https://www.winsoft.sk/win32api.htm to get the update informations that you need. (EDIT: the link is taken from some topic of this forum) By now, I know little bit, seems that Microsoft is still working on this and the things will change (like an extensions of API function). For example the new definition of PROCESS_INFORMATION_CLASS is: PROCESS_INFORMATION_CLASS = ( ProcessMemoryPriority, ProcessMemoryExhaustionInfo, ProcessAppMemoryInfo, ProcessInPrivateInfo, ProcessPowerThrottling, ProcessReservedValue1, ProcessTelemetryCoverageInfo, ProcessProtectionLevelInfo, ProcessLeapSecondInfo, ProcessMachineTypeInfo, ProcessInformationClassMax ); A little bit different from old one.
  4. DelphiUdIT

    Calling routines overhead

    Unless the application is critical to runtimes, the best approach is to focus on timing, code readability, and flexibility. Specifically, break long code into shorter chunks, passing few parameters so as to use only the CPU registers. Use the INLINE directive so that the code can be compiled by "including" it directly in the caller (in this case, the resulting executable will be larger but faster). You can also write parts in assembler to further optimize speed. Be aware, however, that this requires a thorough understanding of the topic and, above all, always provide a Pascal alternative in case the assembler isn't suitable for the processor used at runtime (e.g., Intel vs. ARM) or the platform.
  5. DelphiUdIT

    Calling routines overhead

    The "if" is neutral, since it is alwys execute (may be a very little jmp that are assorbed by cache) ... you can try to invert the two calls and you will (should) see how is the timing. The different times are justified by the overhead (like @PeaShooter_OMO sayd) of the call (load the registers / stack, jmp, load the result / stack, return). It's right to define them INLINE, in this case you have a better timing (you can declare inline one, the other or all two to see the various timing).
  6. david berneda

    Calling routines overhead

    The "if" inside the "for" is also taking time. Try with 2 for loops, one for direct and another for indirect. Also the indirect routine could be marked as "inline" to eliminate the call. This is fine for short small routines.
  7. shineworld

    RAD Studio 10.4.2 crashes upon exit

    My 2 cents. I have been battling, or rather, living with the constant crashing of the Delphi Sydney 10.4.1 IDE for months and months. All I had to do was open the IDE and close it to get the protected memory access error rtl270.bpl I tried uninstalling all plugins (GExpert, Parnassus, etc). No luck. Following your directions I removed the installed libraries one by one and, as Murphy teaches, when I removed the penultimate one the problem disappeared. Basically I was using an old, but not much, library called Graphics32 which in the IDE shutdown phase was sending everything into a tailspin. Updated to the latest version now everything works perfectly.
  8. darnocian

    RAD Studio 10.4.2 crashes upon exit

    I've just been working on some IDE experts/wizards. It can be a little annoying ensuring a clean shutdown sometimes, and not always easy to identify the root problem. I wish the IDE would allow for a registry config variable for displaying/hiding exceptions on shutdown. It is a bit annoying when 3rd parties behave badly. 😉
  9. Rob Truby

    RAD Studio 10.4.2 crashes upon exit

    I've had issues in the past (exception on exiting); I tracked it down to auto loading the desktop when starting/auto saving the desktop on exiting.
  10. You can try this, derivated from Learn Microsoft - EcoQS and updated for Delphi (sorry for errors): //I use _my to discriminate from bundle definitions uses WinApi.Windows; //Add this to uses unit type ///<summary>Documentation: https://docs.microsoft.com/windows/win32/api/processthreadsapi/ne-processthreadsapi-process_information_class</summary> PROCESS_INFORMATION_CLASS_my = ( ProcessMemoryPriority, ProcessMemoryExhaustionInfo, ProcessAppMemoryInfo, ProcessInPrivateInfo, ProcessPowerThrottling, ProcessReservedValue1, ProcessTelemetryCoverageInfo, ProcessProtectionLevelInfo, ProcessLeapSecondInfo, ProcessMachineTypeInfo, ProcessInformationClassMax ); type _PROCESS_POWER_THROTTLING_STATE = record Version: ULONG; ControlMask: ULONG; StateMask: ULONG; end; PROCESS_POWER_THROTTLING_STATE = _PROCESS_POWER_THROTTLING_STATE; PPROCESS_POWER_THROTTLING_STATE = ^PROCESS_POWER_THROTTLING_STATE; const PROCESS_POWER_THROTTLING_CURRENT_VERSION = 1; PROCESS_POWER_THROTTLING_EXECUTION_SPEED = $1; //Redefine API function SetProcessInformation_my(hProcess: THandle; ProcessInformationClass: PROCESS_INFORMATION_CLASS_my; ProcessInformation: Pointer; ProcessInformationSize: DWORD): ByteBool; stdcall; function SetProcessInformation_my; external kernel32 name 'SetProcessInformation' delayed; implementation {$R *.fmx} function SetEfficiencyMode(PID: DWORD): Boolean; var hProcess: THandle; PowerState: PROCESS_POWER_THROTTLING_STATE; begin Result := false; hProcess := OpenProcess(PROCESS_SET_INFORMATION, False, PID); if hProcess <> 0 then begin ZeroMemory(@PowerState, SizeOf(PowerState)); PowerState.Version := PROCESS_POWER_THROTTLING_CURRENT_VERSION; PowerState.ControlMask := PROCESS_POWER_THROTTLING_EXECUTION_SPEED; PowerState.StateMask := PROCESS_POWER_THROTTLING_EXECUTION_SPEED; Result := SetProcessInformation_my(hProcess, Process_Information_Class_my(ProcessPowerThrottling), @PowerState, SizeOf(PowerState)); CloseHandle(hProcess); end; end; procedure TForm1.Button1Click(Sender: TObject); var Success: boolean; begin Success := SetEfficiencyMode(GetCurrentProcessId); if Success then ShowMessage('Efficiency mode activated successfully!') else ShowMessage('Error activating efficiency mode.'); end;
×