Skip to content

Commit

Permalink
[doc] Update pdd25_concurrency (a bit)
Browse files Browse the repository at this point in the history
Hilight our current hybrid threading model.

Several methods are missing:
e.g. wait TASK, threaded writes, Task send, invoke,
pass
  • Loading branch information
Reini Urban committed Dec 12, 2012
1 parent 79e84c9 commit 9f167b1
Showing 1 changed file with 83 additions and 65 deletions.
148 changes: 83 additions & 65 deletions docs/pdds/pdd25_concurrency.pod
Expand Up @@ -11,26 +11,27 @@ Parrot's concurrency models.

=over 4

=item - Parrot supports multiple concurrency models, including POSIX
threads, event-based programming, and asynchronous I/O.
=item - Parrot supports multiple concurrency models, including
green threads, Windows threads, POSIX threads, event-based programming,
and asynchronous I/O.

=item - A concurrency scheduler manages all concurrent tasks
=item - A concurrency scheduler manages all concurrent tasks.

=item - Each interpreter has its own concurrency scheduler
=item - Each interpreter has its own concurrency scheduler.

=item - Concurrency schedulers for different interpreters
communicate and can share tasks
communicate and can share tasks.

=item - A concurrency scheduler may link to other schedulers as a
parent, a child, or an equal
parent, a child, or an equal.

=item - A task is a concurrent unit of work
=item - A task is a concurrent unit of work.

=item - All tasks support a standard interface used by the concurrency
scheduler, but otherwise have a great deal of flexibility in their
implementation
implementation.

=item - Tasks can share PMC variables
=item - Tasks can share PMC variables.

=back

Expand All @@ -46,14 +47,13 @@ A task is a unit of code that can be executed concurrently.

=head2 Implementation

Rather than defining a single canonical threading model, Parrot defines
an infrastructure that supports multiple concurrency models and provides
for interaction between the various models. Parrot already uses multiple
concurrency models for events, threads, async I/O, and exceptions, a
trend that will only continue as we support multiple HLLs and external
threading libraries like Intel's Threading Building Blocks. Designing
for multiple concurrency models also gives Parrot more room to grow as
future models are researched and developed.
Rather than defining a single canonical threading model, Parrot defines an
infrastructure that supports multiple concurrency models and provides for
interaction between the various models. Parrot already uses multiple
concurrency models for events, threads, async I/O, and exceptions, a trend
that will only continue as we support multiple HLLs and external threading
libraries. Designing for multiple concurrency models also gives Parrot more
room to grow as future models are researched and developed.

To avoid conflicts between concurrency models, Parrot provides a single
central concurrency scheduler for each interpreter instance. Each
Expand All @@ -62,15 +62,14 @@ interface. The scheduler can interact with tasks from different models
without direct access to the details of each model.

On multiprocessor systems, the scheduler is responsible for allocating
tasks to processors, or for delegating that allocation to the underlying
OS.
tasks to processors by delegating that allocation to native OS threads.

For the most part, when we talk about concurrency, we mean concurrency
across an interpreter pool. An interpreter pool is a set of interpreter
instances that share common resources: the memory pools, arenas, and
global namespace--pretty much everything except what's in the
interpreter structure itself. They're essentially threads in the OS
sense.
sense and implemented as OS threads.

Another form of concurrency is between completely independent
interpreter instances, each with their own memory pools, arenas,
Expand Down Expand Up @@ -110,7 +109,7 @@ address order). In this model only PMCs can be shared.

=head4 STM Concurrency

Parrot's preferred model of concurrency is based on Software
Older Parrot's preferred a model of concurrency based on Software
Transactional Memory. In this model, rather than locking a shared
variable while performing a series of operations on it, the changes are
bundled into a transaction that acts as an atomic unit.
Expand All @@ -132,6 +131,27 @@ safety mode, STM tasks may be configured to fail validation on any
transaction attempting to commit to a variable locked by a mutex/lock
task.

=head4 Intel Threading Building Blocks

Threading Building Blocks (TBB) is a library of tools for data-parallel
programming, dividing large data sets into small pieces so that
operations on those data-sets can be parallelized across multiple
processors.

Parrot might provide two levels of integration with TBB: an interface for
TBB's scheduling to interact with the central concurrency scheduler, and
an interface for developers to access the TBB routines from within
PIR/PASM.

Like Parrot, TBB is task-based. Since TBB performs its own scheduling,
TBB tasks in Parrot will be given a lightweight scheduler that only has
the responsibility of passing messages, events, etc, back and forth
between the TBB task and the central scheduler. TBB tasks will not share
variables with any other types of concurrent tasks in Parrot.

Note that since TBB is a C++ library, it is only available when Parrot
is compiled with a C++ compiler.

=head4 POSIX Concurrency

This is the POSIX "share-everything" style of threading, such as is used
Expand All @@ -143,9 +163,32 @@ Butenhof.]

This is the Perl 5 "iThreads" threading model. In this model no data is
shared implicitly, and all sharing must be done on purpose and
explicitly. It resembles the Unix
fork-process-with-shared-memory-segment model, not a surprise as it was
originally developed with emulation of Unix's fork system in mind.
explicitly. It resembles the Unix fork process with shared memory segment
model, not a surprise as it was originally developed with emulation of
Unix's fork system in mind.

=head4 Hybrid-thread Concurrency (current)

Lightweight "green" threads (i.e. Task) are used as messages in a system
where reading shared variables is allowed but only the one owner thread
may write to it.

With our current hybrid threads model all data sharing is implemented
through Proxy PMCs. Reading foreign data is transparent, writing must
be done via writer subs scheduled in the owners Task. To reduce latency,
the task is flagged to run immediately. The data-owning interpreter will
preempt the currently running task and process the new write task.
Thus proxies allow a nearly lock-free multithreading implementation.

Each task is assigned a fixed amount of execution time. After this time is
up a timer callback sets a flag which is checked at execution of every
branch operation. Since the interpreter's state is well defined at this
point, its internal consistency is guaranteed. The same holds for the
GC. Since task preemption is only done while executing user-level code, the
GC can do its work undisturbed and without the need for measures like
locking. Since user-level code is allowed to disable the scheduler, it can
be guaranteed to run undisturbed through critical sections.


=head4 Independent Concurrency

Expand All @@ -157,27 +200,6 @@ Note that independent tasks may still communicate back and forth by
passing either atomic things (ints, floats, and pointers) or static
buffers that can become the property of the destination thread.

=head4 Intel Threading Building Blocks

Threading Building Blocks (TBB) is a library of tools for data-parallel
programming, dividing large data sets into small pieces so that
operations on those data-sets can be parallelized across multiple
processors.

Parrot will provide two levels of integration with TBB: an interface for
TBB's scheduling to interact with the central concurrency scheduler, and
an interface for developers to access the TBB routines from within
PIR/PASM.

Like Parrot, TBB is task-based. Since TBB performs its own scheduling,
TBB tasks in Parrot will be given a lightweight scheduler that only has
the responsibility of passing messages, events, etc, back and forth
between the TBB task and the central scheduler. TBB tasks will not share
variables with any other types of concurrent tasks in Parrot.

Note that since TBB is a C++ library, it is only available when Parrot
is compiled with a C++ compiler.

=head3 Concurrency Scheduler API

The concurrency scheduler has two parts, a Scheduler PMC, which has an
Expand Down Expand Up @@ -218,31 +240,27 @@ schedulers, both local to the current interpreter and remote.
The task list is a simple unordered integer indexed data structure, currently
implemented as a hash. Each task in the list has an integer ID assigned when
it is first inserted into the list. A task retains the same ID throughout its
lifetime, and the ID is not reused once a task is finalized. (The data
structure is currently implemented as a hash so that it only takes up the
memory required for currently living tasks. A task list for a particular
program may use thousands of task IDs, but only need memory allocated for a
handful of elements at any given moment.)

The task rank index is calculated based on the type, priority rating, age of
the tasks in the task list. The index is a simple array, and in general the
top (zeroth) element in the array is the next one to receive attention. The
index is recalculated regularly as new tasks are inserted into the task list,
existing tasks are modified or completed, and as time progresses so the age of
some tasks pushes them to a higher priority. Because of the regular
recalculation, the rank index may cache some frequently-accessed and rarely
changing data from the tasks (though it is not required to do so). (As a later
optimization, some data structure other than an array may be used to speed up
rank recalculation. For example, with a hash of hashes of arrays keyed on task
attributes, the process of inserting new tasks at a relative priority to other
existing tasks could be performed without shifting the rank of all lower
ranked tasks.)
lifetime, and the ID is not reused once a task is finalized. The data
structure is currently implemented as pre-allocated array, the number of CPU's
plus one, overridable by --numthreads <N>.

Currently a task is implemented as OS thread so ranking is done by the OS.
Prioritization is done with the interpreter method 'schedule_proxied'.
Previous versions used a task rank index, calculated based on the type,
priority rating, age of the tasks in the task list. The index is a simple
array, and in general the top (zeroth) element in the array is the next one
to receive attention. The index is recalculated regularly as new tasks are
inserted into the task list, existing tasks are modified or completed, and
as time progresses so the age of some tasks pushes them to a higher
priority. Because of the regular recalculation, the rank index may cache
some frequently-accessed and rarely changing data from the tasks (though it
is not required to do so).

The list of handlers is a simple stack of handler PMCs currently waiting for
an appropriate task (event, exception). See PDD 24 on Events for more details
on event handlers.

=head4 Flags
=head4 Flags (old)

PMC flags 0-7 are reserved for private use by a PMC. The scheduler uses flag 0
to indicate whether the priority index is currently valid or needs to be
Expand Down

0 comments on commit 9f167b1

Please sign in to comment.