[FEATURE REQUEST] For change current or adding new table for message handling
Original Reporter info from Mantis: Bishop
-
Reporter name: Emelyanov Roman
Original Reporter info from Mantis: Bishop
- Reporter name: Emelyanov Roman
Description:
Further I will try to describe why and why I consider it necessary.
Now i develop application that use actor model, so there is many message processing in it. Pascal have a great thing for it TObject.Dispatch and message handling procedure declareble via 'message' key word. But internal mechanics of TObject.Dispatch is very slow.
First of all searching of message handler via linear search (i make small patch to change it to binary search, but its still not so fast like i want).
Then, if handler is in some perent classes we need make handler search on every perent till perent with handler. This is huge count of memory access (and most of it is dependent memory access). This make app with extensive message processing very slow and uneffective. Especially on NUMA-machine (every multi-socket server, especially 8+ sockets) because all static data of process (including VMT, message tables and etc.) be on single NUMa-node (so all other nodes make reference to non-local memory).
So i have my proposal to change this mechanics.
I make small procedures to show my concept (you can see it below). The main idea in use handler vector plus index of minimal and maximal messages in it. All holes point to default message handles. Pointer to this vector stored in VMT (classes with no change in message handlers vector theoretically can share same message handler vector). This will allow make search of message handler O(1) with very small count of memory access (price is some memory usage). Possible generation of this vector must be optional.
Additional information:
Type
TMessageProcedure = Procedure(Self: TObject; Var Message);
PMessageVector = ^TMessageVector; TMessageVector = Record Min, Max: Word32; Entries: Array [0..0] of TMessageProcedure; End;
Class Procedure TObject.GenMessageVector; //THIS MUST BE DONE BY COMPILER
Var
Min, Max : Word32;
Cur, Cnt : Word32;
Vmt : PVmt;
Table : PMessageTable;
Entry : PMessageEntry;
Vector : PMessageVector;
Begin
Min := $FFFFFFFF; Max := 0; Vmt := PVmt(ClassType);
While Assigned(Vmt) Do
Begin
Table := Vmt^.vDynamicTable;
If Assigned(Table) Then
Begin
If Min > Table^.Entries[ 0].Index Then Min := Table^.Entries[ 0].Index;
If Max < Table^.Entries[Table^.Count-1].Index Then Max := Table^.Entries[Table^.Count-1].Index;
End;
Vmt := Vmt^.vParent;
End;
If Min > Max Then Exit; //DONT NEED GET vMessageVector
Vector := Allocate(4+4+SizeOf(Pointer)*(Max-Min+1));
Vector^.Min := Min;
Vector^.Max := Max;
Vmt := PVmt(ClassType);
While Assigned(Vmt) Do
Begin
Table := Vmt^.vDynamicTable;
If Assigned(Table) Then
Begin
Entry := @Table^.Entries[0]; Cur := 0; Cnt := Table^.Count;
While Cur < Cnt Do
Begin
If Vector^.Entries[Entry^.Index-Min] = Nil Then Vector^.Entries[Entry^.Index-Min] := Entry^.Proc;
Inc(Entry); Inc(Cur);
End;
End;
Vmt := Vmt^.vParent;
End;
For Cur := Min to Max Do If Vector^.Entries[Cur] = Nil Then Vector^.Entries[Cur] := @TObject.DefaultHandler;
//STORE Vector LIKE ALL OTHER VMT RELATED TABLES
End;
Procedure TObject.Dispatch(Var Message);
Var
Index : Word32;
Vector : PMessageVector;
Begin
Index := Word32(Message);
Vector := PVmt(ClassType)^.vMessageVector; //NEW MESSAGE HANDLING VECTOR GENERATED BY COMPILER
If Assigned(Vector) And (Vector.Min <= Index) And (Vector.Max >= Index) Then Vector.Entries[Index](Self, Message)
Else DefaultHandler(Message);
End;
Mantis conversion info:
- Mantis ID: 31124
- Version: 3.1.1
- Monitored by: » Bishop (Emelyanov Roman)