## Learning Objectives
* Learn about contexts and what they are used for
* Learn about how create dependencies across devices
* Learn about moving data between devices
#### What is a context
* In SYCL the underlying execution and memory resources of a platform and its devices is managed by creating a context
* A context represents one or more devices, but all devices must be associated with the same platform
#### Implicit context
![Queue](../common-revealjs/images/queue-5.png "SYCL-Queue")
* Every `queue` requires a `context` to manage
memory allocation and data movement.
* If one is not specified explicitly a `queue` will
create a `context` implicitly.
#### Shared context
![Queue](../common-revealjs/images/queue-1.png "SYCL-Queue")
* In order to ensure data is efficiently moved
between devices in the same platform you can create
a common `context`.
#### Creating queues
![Queue](../common-revealjs/images/queue-3.png "SYCL-Queue")
* You can then create a `queue` for each of the
devices from the common `context`.
#### Creating an implicit context
auto defaultQueue = queue{};
* A default constructed queue object will use the
`default_selector` to choose a device and create an
implicit `context`.
#### Creating a context from devices
auto sharedContext = context{{cpuDevice, gpuDevice}};
* You can construct a `context` from a `std::vector` of
`device`s.
#### Creating a context from a platform
auto sharedContext = context{intelPlatform};
* You can construct a `context` from a `platform` in
which case it will be associated with all of the devices
of that `platform`.
#### Targeting multiple devices
* A single SYCL application will often want to
target multiple different devices.
* This can be useful for task level parallelism and
load balancing.
* When doing so you want to ensure that data is
moved between devices in a `context` efficiently.
#### Moving between devices
* Often in heterogeneous applications it's necessary to
move data from one device to another.
* In the USM model this is done explicit via `memcpy` as
we've seen before.
* In the buffer/accessor model this is done
automatically based on dependency analysis.
#### Accessing data on a device
* Remember that a `buffer` will move data to a
device when required by an `accessor`.
![Buffer Copied](../common-revealjs/images/buffer-hostmemory-accessor-cg-device.png "Buffer Copied")
#### Accessing data on another device (same context)
* Now if a `buffer` is accessed on a device when the
latest copy of the data is on another device, the
data will be moved between the devices.
* If the two devices are of the same context the
data can be copied directly.
![Buffer Copied](../common-revealjs/images/buffer-copied.png "Buffer Copied")
#### Accessing data on another device (different context)
* If the devices are of different `context`s the
data must be copied via host memory.
* It's important to consider this as it could incur
further overhead when moving data between devices.
![Buffer Copied](../common-revealjs/images/copy-via-host.png "Buffer Copied")
#### Moving between devices (buffer/accessor)
![SYCL](../common-revealjs/images/moving_data_between_devices.png "SYCL")
* If a `buffer` is accessed by kernel functions in two different devices commands are enqueued to automatically move the data to the devices it is being accessed on.
* If both of those devices are associated with the same context (i.e. same vendor) then the copy is direct.
* Otherwise the copy will generally go via the host and has additional overhead.
#### Exercise
Code_Exercises/Multiple_Devices/source
Write a SYCL application that splits up a task between
two devices.