Reputation: 374
For a hobby interpreter project I am looking for advice on a performance-related question regarding task synchronization. A scheduler must map new green tasks to real tasks, each of which holds its own linked list of green tasks.
The problem: How do I synchronize the addition of a green task to a running real task with the least overhead possible? In earlier tests I have found out that making the linked list a protected object slows down access to it from within its own real task tremendously. To give you an idea of how tight the interpreter loop is currently in the single-task version:
while not Is_Empty (Global_State.GTasks) loop
Current_Task := Next (Global_State.GTasks);
Global_State.Pram (Current_Task.PC).all (Global_State, Current_Task);
Current_Task.PC := Current_Task.PC + 1;
Update (Global_State.GTasks, Current_Task);
end loop;
(Update still copies but I can later get rid of that.)
My tests have indicated that even minimal changes to this loop can slow down interpretation tremendously. Imagine that instead of in Global_State, GTasks resides as a local variable in the task executing this loop. I only need to synchronize access to GTasks when the scheduler adds a new GTask from the outside the task which runs this loop.
What would you recommend in this situation?
Upvotes: 1
Views: 228
Reputation: 8522
(The following is contingent on my having a reasonable understanding of the question.)
If one can go forward with the "GTasks resides as a local variable in the the task" conjecture, then perhaps incorporating a conditional accept may work--I have no idea what the performance hit would be, it's just an idea.
while not Is_Empty (GTasks) loop
Current_Task := Next (GTasks);
Global_State.Pram (Current_Task.PC).all (Global_State, Current_Task);
Current_Task.PC := Current_Task.PC + 1;
Update (GTasks, Current_Task);
select
accept Accept_New_Task(Green_Task : Green_Task_Type) do
Append(GTasks, Green_Task);
end Accept_New_Task;
else
null;
end select;
end loop;
Or perhaps only periodically check for new tasks, say, every so-many PC increments? (Again, no promises on the performance hit.)
while not Is_Empty (GTasks) loop
Current_Task := Next (GTasks);
Global_State.Pram (Current_Task.PC).all (Global_State, Current_Task);
Current_Task.PC := Current_Task.PC + 1;
Update (GTasks, Current_Task);
if PC_Increments = Check_For_New_Tasks then
select
accept Accept_New_Task(Green_Task : Green_Task_Type) do
Append(GTasks, Green_Task);
end Accept_New_Task;
else
null;
end select;
PC_Increments := 0;
else
PC_Increments := PC_Increments + 1;
end if;
end loop;
Upvotes: 2