Parallel IT · Pyjama
Pyjama Tutorial — Virtual Target
From v2.0, Pyjama supports the virtual target. Several new directives are introduced:
//#omp target virtual
//#omp wait
//#omp async-call
//#omp async
1. What is a virtual target?
In standard OpenMP, the target directive offloads a code region to an accelerator such as a
GPU or FPGA. With a virtual target, the region is also offloaded to a target — but that target
is virtual: a syntax-level abstraction of a thread-pool executor. The region is executed by
the executor named by the target, and because a virtual target shares the host’s memory, the
data context is unchanged on entering the block.
2. How to use virtual targets
Create or register a virtual target before use. A single thread can be registered as a virtual target (e.g. making the event dispatch thread one):
Pyjama.omp_register_as_virtual_target(String targetName);
Or create a new virtual target backed by a thread pool:
Pyjama.omp_create_virtual_target(String targetName, int threadNum);
3. Tell Pyjama which GUI framework you use
To use virtual targets in a GUI application, tell Pyjama which platform you’re on (Java Swing, Android, or JavaFX) so it knows how to dispatch code to the event dispatch thread:
Pyjama.omp_set_platform(Platform);
4. When to use virtual targets
A typical scenario is an event handler. Without directives, the whole handler runs on the EDT.
Set up the platform and targets at the start of main:
Pyjama.omp_set_platform(Platform.Swing);
Pyjama.omp_register_as_virtual_target("edt");
Pyjama.omp_create_virtual_target("worker", 3);
Offload heavy computation to the background with //#omp target virtual(worker), and push UI
updates back to the EDT with //#omp target virtual(edt):
void buttonOnClick() {
Panel.showMsg("Started EDT handling");
Info info = Panel.collectInput();
//#omp target virtual(worker) nowait
{
int hscode = getHashCode(info);
downloadAndCompute(hscode);
//#omp target virtual(edt)
Panel.showMsg("Finished!");
}
}
void downloadAndCompute(int hs) {
Buffer buf = networkDownload(hs);
Image img = formatConvert(buf);
//#omp target virtual(edt)
Panel.displayImg(img);
}
The event handler is transformed without changing the original sequential code, freeing the EDT to handle other events while heavy work runs in the background.
5. Asynchronisation
The clauses used after //#omp target virtual give the region its asynchronous nature:
- Default (wait) — with no asynchronous clause, the region runs synchronously: the encountering thread busy-waits until the target finishes.
- nowait — the encountering thread skips the block, leaving it as an asynchronous task, and continues; there is no completion notification.
- name_as / wait — like nowait, but a task identifier (name-tag) is created so the thread can later synchronise via
wait(name-tag). Blocks may share a name-tag; the wait then suspends until all instances finish. - await — a wait policy where, during the wait, control jumps out of the current function back to its caller; when the target finishes, the function resumes where it suspended.
6. Using await and async functions
A function containing one or more await target blocks is an async function: it can run
asynchronously, is pausable and resumable, contains await/async-call directives, and is
annotated with //#omp async:
//#omp async
int myAsyncFunction(int work) {
before();
//#omp target virtual(worker) await
{
computation(work);
}
after();
}
Invoke an async function with async-call (which makes the caller async too):
//#omp async
int async_bar(Info info) {
before();
int a;
//#omp async-call(int foo(int))
{
a = foo(1);
}
after();
}
A normal call invokes it synchronously, like an ordinary function.
7. What’s more?
For details, see X. Fan, O. Sinnen, N. Giacaman (2016), “Towards an Event-Driven Programming Model for OpenMP,” P2S2 (with ICPP 2016), Philadelphia, USA — and the Pyjama Quick Reference Card for the complete set of directives and runtime functions.