Changes in / [4c2e561:7f1be01]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/colby_parsons_MMAth/text/actors.tex

    r4c2e561 r7f1be01  
    538538% Through these behaviours, a worker inserts messages onto its own and other worker ready-queues.
    539539To steal, a thief takes work from a victim's ready queue, so work stealing always results in a potential increase in contention on ready queues between the victim gulping from a queue and the thief stealing the queue.
    540 This contention can reduce the victim's throughput.
     540This contention can slows down the victim's throughput.
    541541Note, the data structure used for the ready queue is not discussed since the largest cost is the mutual exclusion and its duration for safely performing the queue operations.
    542542
    543543The stealing mechanism in this work differs from most work-stealing actor-systems because of the message-centric (inverted) actor-system.
    544 Actor systems, such as Akka~\cite{Akka} and CAF~\cite{CAF} using actor-centric systems, steal by dequeuing an actor from a non-empty actor ready-queue and enqueue\-ing to an empty ready-queue.
     544Actor systems, such as Akka~\cite{Akka} and CAF~\cite{CAF} using actor-centric systems, steal by dequeuing from a non-empty actor ready-queue and enqueue\-ing to an empty ready-queue.
    545545% As an example, in CAF, the sharded actor ready queue is a set of double-ended queues (dequeues).
    546546In \CFA, the actor work-stealing implementation is unique because of the message-centric system.
    547547With this approach, it is impractical to steal actors because an actor's messages are distributed in temporal order along the message queue.
    548 To ensure sequential actor execution and \gls{fifo} message delivery in a message-centric system, stealing requires finding and removing \emph{all} of an actor's messages, and inserting them consecutively in another message queue.
     548To ensure sequential actor execution and \gls{fifo} message delivery in a message-centric system,  stealing requires finding and removing \emph{all} of an actor's messages, and inserting them consecutively in another message queue.
    549549This operation is $O(N)$ with a non-trivial constant.
    550550The only way for work stealing to become practical is to shard each worker's message queue, which also reduces contention, and to steal queues to eliminate queue searching.
    551551
    552 Given queue stealing, the goal of the presented stealing implementation is to have an essentially zero-contention-cost stealing mechanism.
     552\begin{figure}
     553\begin{center}
     554\input{diagrams/steal.tikz}
     555\end{center}
     556\caption{Queue Stealing Mechanism}
     557\label{f:steal}
     558\end{figure}
     559
     560Given queue stealing, the goal of the presented work stealing implementation is to have an essentially zero-contention-cost stealing mechanism.
    553561Achieving this goal requires work stealing to have minimal (practically no) effect on the performance of the victim.
    554562The implication is that thieves cannot contend with a victim, and that a victim should perform no stealing related work unless it becomes a thief.
    555563In theory, this goal is not achievable, but practical results show the goal is virtually achieved.
    556564
    557 One important lesson learned while working on \uC actors~\cite{} and through discussions with fellow student Thierry Delisle, who examined work-stealing for user-threads in his Ph.D.~\cite{Delisle22}, is \emph{not} to aggressively steal.
     565One important lesson learned while working on \uC actors~\cite{} and through discussions with fellow student Thierry Delisle, who examined work-stealing for user-threads in his Ph.D., is \emph{not} to aggressively steal.
    558566With reasonable workloads, being a thief should be a temporary state, \ie eventually work appears on the thief's ready-queues and it returns to normal operation.
    559567Furthermore, the act of \emph{looking} to find work is invasive (Heisenberg uncertainty principle), possibly disrupting multiple victims.
     
    561569Note, the cost of stealing is not crucial for the thief because it does not have anything else to do except poll or block.
    562570
    563 The outline for lazy-stealing by a thief is: select a victim, scan its queues once, and return immediately if a queue is stolen.
     571As such a lazy-stealing approach is used; a thief select a victim, scan its queues once, and return immediately if a queue is stolen.
    564572The thief then returns to normal operation and conducts a regular scan over its own queues looking for work, where stolen work is placed at the end of the scan.
    565573Hence, only one victim is affected and there is a reasonable delay between stealing events by scanning all the thief's ready queue looking for its own work.
     
    572580Stealing a queue is done wait-free (\ie no busy waiting) with a few atomic instructions that only create contention with other stealing workers, not the victim.
    573581The complexity in the implementation is that victim gulping does not take the mailbox queue;
    574 rather it atomically transfers the mailbox nodes to another list leaving the mailbox empty, \ie it unlinks the queue nodes from the top pointer leaving the original list empty.
    575 Hence, the original mailbox is always available for new message deliveries.
     582rather it atomically transfers the mailbox queue to another list leaving the mailbox empty.
     583Hence, the original list is available for new message deliveries.
    576584However, this transfer logically subdivides the mailbox, and during this period, the mailbox cannot be stolen;
    577585otherwise there are two threads simultaneously running messages on actors in the two parts of the mailbox queue.
     
    579587Hence, a thief checks if a queue is eligible and non-empty before attempting an atomic steal of a queue.
    580588
    581 Figure~\ref{f:steal} shows the queue architecture and stealing mechanism.
    582 Internally, the mailbox queues are accessed through two arrays of size $N$, which are shared among all workers.
    583 There is an array of mailbox queues, @mailboxes@, and an array of pointers to the mailboxes, @worker_queues@:
    584 \begin{cfa}
    585 struct work_queue {
    586         spinlock_t mutex_lock;                          $\C[2.75in]{// atomicity for queue operations}$
    587         copy_queue * owned_queue;                       $\C{// copy queue}$
    588         copy_queue * c_queue;                           $\C{// current queue}$
    589         volatile bool being_processed;          $\C{// flag to prevent concurrent processing}$
    590 };
    591 work_queue * mailboxes;                                 $\C{// master array of work request queues}$
    592 work_queue ** worker_queues;                    $\C{// secondary array of work queues to allow for swapping}\CRT$
    593 \end{cfa}
    594 A send inserts a request at the end of a @mailboxes@.
    595 A steal swaps two pointers in @worker_queues@.
     589Internally, the mailbox queues are accessed through two arrays of size $N$, that are shared among all workers.
     590There is an array of mailbox queue objects @mailboxes@, and an array of pointers to the mailbox objects, @worker_queues@:
     591\begin{cfa}
     592work_queue * mailboxes;                   // master array of work request queues
     593work_queue ** worker_queues;                // secondary array of work queues to allow for swapping
     594\end{cfa}
     595A diagram of the queue architecture and stealing mechanism is shown in Figure~\ref{f:steal}.
     596
     597When a send happens, it inserts a request directly into one of the @mailboxes@, but when a steal happens, two pointers in @worker_queues@ are swapped.
    596598Conceptually, @worker_queues@ represents the ownership relation between mailboxes and workers.
    597599Given $M$ workers and $N$ mailboxes, each worker owns a contiguous $M$/$N$ block of pointers in @worker_queues@.
     
    601603As such, operations can happen on the queues independent of stealing, which avoids almost all contention between thief threads and victim threads.
    602604
    603 \begin{figure}
    604 \begin{center}
    605 \input{diagrams/steal.tikz}
    606 \end{center}
    607 \caption{Queue Stealing Mechanism}
    608 \label{f:steal}
    609 \end{figure}
    610 
    611605To steal a queue, a thief does the following:
    612606\begin{enumerate}[topsep=5pt,itemsep=3pt,parsep=0pt]
    613607\item
    614 chooses a victim.
    615 Victim selection heuristics are independent of the stealing mechanism and discussed in Section~\ref{s:victimSelect}.
     608chooses a victim. Victim selection heuristics are independent of the stealing mechanism and will be discussed in Section~\ref{s:victimSelect}.
    616609
    617610\item
    618611scan the victim's $M$/$N$ range of @worker_queues@ and non-atomically checks each mail queue to see if it is eligible and non-empty.
    619 If a match is found, the thief attempts to steal the queue by swapping the appropriate victim worker-queue pointer with an empty thief's pointer, where the pointers come from the victim's and thief's ranges, respectively.
    620 % The swap races to interchange the appropriate victim's mail-queue pointer with an empty mail-queue pointer in the thief's @worker_queues@ range.
    621 This swap can fail if another thief steals the queue, which is discussed further in Section~\ref{s:swap}.
    622 % Note, a thief never exceeds its $M$/$N$ worker range because it is always exchanging queues with other workers.
    623 If no appropriate victim mailbox is found, no swap is attempted.
    624 
    625 \item
    626 stops searching after a successful queue steal, a failed queue steal, or all queues in the victim's range are examined.
    627 The thief then resumes normal execution and ceases being a thief.
    628 Hence, it iterates over its own worker queues because new messages may have arrived during stealing, including ones in the potentially stolen queue.
     612If one such mail queue is found, the thief attempts to steal the queue by swapping two pointers in @worker_queues@.
     613The swap races to interchange the non-empty mail-queue pointer from the victim's @worker_queues@ range with an empty mail-queue pointer in the thief's @worker_queues@ range.
     614This swap can fail if another thief steals the queue, which will be discussed further in Section~\ref{s:swap}.
     615Note, a thief never exceeds its $M$/$N$ worker range because it is always exchanging queues with other workers.
     616If no such mail queue is found, no swap is attempted.
     617
     618\item
     619stops searching after a successful queue steal, a failed queue steal or all queues in the victim's range are examined.
     620The thief then resumes normal execution and ceases being a thief; it returns to its own queues and iterates over them, because new messages may have arrived during stealing, including ones in the potentially stolen queue.
    629621Stealing is only repeated after the worker completes two consecutive iterations over its owned queues without finding work.
    630622\end{enumerate}
    631623
    632 As mentioned, there is a race between a victim gulping and a thief stealing because gulping partitions a mailbox queue making it ineligible for stealing.
    633 Furthermore, after a thief steals, there is moment when victim gulps but the queue no longer
    634 % This algorithm largely eliminates contention among thieves and victims except for the rare moment when a victim/thief concurrently attempt to gulp/steal the same queue.
    635 % Restating, when a victim operates on a queue, it first copies the queue pointer from @worker_queues@ to a local variable (gulp).
    636 % It then uses that local variable for all queue operations until it moves to the next index of its range.
    637 % This approach ensures any swaps do not interrupt gulping operations, however this introduces a correctness issue.
    638 % There is a window for a race condition between the victim and a thief.
    639 % Once a victim copies the queue pointer from @worker_queues@, a thief could steal that pointer and both may try to gulp from the same queue.
    640 % These two gulps cannot be allowed to happen concurrently.
    641 % If any behaviours from a queue are run by two workers at a time it violates both mutual exclusion and the actor ordering guarantees.
    642 To avoid this race, each mailbox header stores a @being_processed@ flag that is atomically set to @true@ when a queue is gulped.
     624This approach largely eliminates contention among thieves and victims except for the rare moment when a thief steals a queue and the victim and thief concurrently attempt to gulp the same queue.
     625When a victim operates on a queue, it first copies the queue pointer from @worker_queues@ to a local variable.
     626It then uses that local variable for all queue operations until it moves to the next index of its range of the queue array.
     627This ensures that any swaps do not interrupt gulping operations, however this introduces a correctness issue.
     628There is a window for a race condition between the victim and a thief.
     629Once a victim copies the queue pointer from @worker_queues@, a thief could steal that pointer and both may try to gulp from the same queue.
     630These two gulps cannot be allowed to happen concurrently.
     631If any behaviours from a queue are run by two workers at a time it violates both mutual exclusion and the actor ordering guarantees.
     632To avoid concurrent gulps, each queue stores a @being_processed@ flag that is atomically set to @true@ when a queue is gulped.
    643633The flag indicates that a queue is being processed by a worker and is set back to @false@ once the local processing is finished.
    644634If a worker, either victim or thief, attempts to gulp a queue and finds that the @being_processed@ flag is @true@, it does not gulp the queue and moves on to the next queue in its range.
Note: See TracChangeset for help on using the changeset viewer.