Thursday, January 10, 2008

Performance issue of TAction

If you have never heard about TAction or used it, you are definitely not a Delphi developer ^^) This component simplifies the UI work. I mentioned once accidentally, that the CPU usage became abnormally high, when mouse was moved quickly on the main form. Spy++ tells, that massive WM_UPDATE message were sent, when mouse was moving fast over the main form. So I took a closer look into the details and found out that TContainedAction.Update() was executed many times by the TActionManager. As it is described in Help "this method triggers the OnUpdate event handler. ... When the application is idle, the OnUpdate event occurs for every action." The idle status will be changed very frequently. I have more than 100 TAction controls on the main form, which means TContainedAction.Update() was executed more than 100 times in a very short time. This explains, why my application became a CPU usage monster.

Solution

If your application does not handle any OnUpdate events, it really makes sense to accelerate TContrainedAction.Update().

My solution is to replace the original method is an empty method.

uses
FastcodePatch {MPL http://fastcode.sourceforge.net/};

procedure TContainedActionUpdateStub;
asm
call TContainedAction.Update;
end;

type
TContainedActionPatch = class(TContainedAction)
public
function Update: Boolean; override;
end;

function TContainedActionPatch.Update: Boolean;
begin
Result := False;
end;

// Disallows the TContainedAction.Update to trigger TAction.OnUpdate()
procedure DisableTContainedActionUpdate;
begin
FastcodeAddressPatch(
FastcodeGetAddress(@TContainedActionUpdateStub),
@TContainedActionPatch.Update);
end;

The best place to run this patch is in YourForm.OnCreate() event. If you want to make a permanent patch, you can either modify TContainedAction.Update in ActnList.pas directly, or submit it to CodeGear's quality center.

Conclusion

In this article [1], I have shown a potential performance issue by using massive TxxxxAction components. I have also implemented a patch to fix this issue. Here is the patch

References

  1. The Chinese version of this article (on my blog @csdn)
 

1 comment:

Duncan said...

We were about to implement this patch, but alternate solution is to hook the OnUpdate event on the Action List and set handled = true. This stops the default processing for updates by the Action list.