Pyjama tutorial – Virtual Target


From v2.0, Pyjama supports Virtual Target.There are several new directives are introduced:
	
	//#omp target virtual
	//#omp wait
	//#omp async-call
	//#omp async
	
	

1. What is a virtual target?

People who have experience with OpenMP may have been familiar to target directive. The original OpenMP target directive is used to offload the target code region to an accelerator (e.g. GPU, FPGA). For the concept of virtual target, the target code region is also offloaded to the target, but in fact, this target is virtual.

A virtual target is a syntax-level abstraction of a thread pool executor, such that the target region block is executed by the executor specified by the target-name. a virtual target actually shares the same memory as the host holds, so the data context remains the same when entering the target code block.

2. How to use virtual targets?

Before you use virtual targets, you have to create or register them. Programmers can create virtual targets by two ways.

First, a single thread can be registered as a virtual target. People may want the EDT be a virtual target. This can be achieved by calling the Pyjama runtime function. This function will make the current thread as a virtual target named targetName:

Pyjama.omp_register_as_virtual_target(String targetName);

Also, programmers can create a new virtual target by calling:

Pyjama.omp_create_virtual_target(String targetName, int threadNum);

This function will create a virtual target named targetName and with a thread pool and the thread number is threadNum.

3. Tell Pyjama what GUI framework you are using.

You may use Pyjama virtual target in your GUI application. However, Pyjama does not know how to dispatch the target code to the EDT unless you tell it what GUI platform you are using. For current version, Pyjama can support Java Swing, or Android, or JavaFX. Programmers need explicitly call Pyjama runtime function in the beginning of the program and tell Pyjama runtime what platform is using:

Pyjama.omp_set_platform(Platform);

4. When to use the virtual targets?

A typical scenario of using virtual target is in an event handler. For example, the following code snippet shows an event handler and when a button is clicked, the buttonOnClick() is executed. If there is no directive added, the entire event handler will be executed by the EDT.

Before using the virtual target, in the beginning of the main function, programmers should create the corresponding virtual targets and declare the Platform.

Pyjama.omp_set_platform(Platform.Swing);
Pyjama.omp_register_as_virtual_target(“edt”);
Pyjama.omp_create_virtual_target(“worker”, 3);

Then, you can use virtual target, to offload the heavy-load computation to the background, by using //#omp target virtual(worker). In some circumstance, you may discover some UI manipulations should be executed by the EDT but they are already offloaded to the worker virtual target. What you need to do is transfer the UI manipulations back to the EDT again! Use //#omp target virtual(edt) to make the UI update related statement to be submitted back to the EDT.

Here you see, without changing the original sequential code, you transfer the event handler into a better way that make the EDT have more time to handle other events and the heavy-load computations are offloaded to the background.


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);
}

5. Asynchronization

You may discover that there are some clauses are used after the //#omp target virtual directive, such as nowait, name_as, await. We call them asynchronous-property-clause. This kind of clauses give the target region block asynchronous nature. More specifically:

  • Default(wait). If there is no asynchronous-property-clause is used, the target region block run in a synchronous way. That means the encountering thread will busy-wait until the target code block is finished by the specified target. The target code block still run in a synchronous way.
  • nowait. The encountering thread directly skips the target block and leaves the target block as an asynchronous task, then continues executing statements following the block. There is no notification when the target block is finished.
  • name_as/wait. Like nowait, the encountering thread directly skips the target block and leaves the target block as an asynchronous task, then continues executing statements following the block. Unlike nowait, a task identifier name-tag is created that enables the encountering thread to explicitly synchronize with the task by using the associated wait(name-tag) clause later in the code. Notice that different target blocks are allowed to share the same name-tag, such that when the wait clause is applied with that name-tag, the encountering thread suspends until all the name-tag asynchronous target block instances finish.
  • await. The await asynchronization policy is a wait policy, with the important difference that during the wait period the control flow jumps out of the current function and back to its caller. When the target code is finished, the function resumes its execution from where it previously suspended.
  • 6. How to use await & What is an async function?

    You may find await asynchronous-property-clause is a little bit harder to understand than the rest clauses. In fact, it is not as difficult as you think. Await is much useful and easy-to-use and it can help you for the most of the situations. You needn't care about how the runtime resume the execution once the await target block is finished. You only need to know if a function contain one or more await target block, this function will be regarded as an async function:

    So what is an async function?

  • Can be run asynchronously
  • Pausable & resumable
  • Contain one or more await/async-call directives
  • Should be annotated with //#omp async
  • For example, this is an sync function:

    
    //#omp async
    int myAsyncfunction(int work) {
        before();
        //#omp target virtual(worker) await
        {
            computation(work);
        }
        after();
    }
    
    

    This is not an async function:

    
    int mycfunction(int work) {
        before();
        //#omp target virtual(worker) nowait
        {
            computation(work);
        }
        after();
    }
    
    

    How to invoke an async function?

    For instance, here is an async function:

    
    //#omp async
    int foo(int work) {
        //#omp target virtual(worker) await
        {
            cpu_bound_computation(work);
        }
    }
    
    

    You can invoke the async function in two ways:

  • Use async-call make the caller function async too; Notice the function uses async-call will cause this function async as well.
  • 
    //#omp async
    int async_bar(Info info) {
        before();
        int a;
        //#omp async-call(int foo(int))
        {
            a = foo(1);
        }
        after();
    }
    
    
  • Normal call make the function run as a normal synchronous behavior; This will call the function synchronously as like invoking a normal function.
  • 
    int bar(Info info) {
        before();
        int a;
        //This call invoke the foo like normal style.
        {
            a = foo(1);
        }
        after();
    }
    
    

    7. What's more?

    For more information about virtual target, you can download the published paper and see more details.

    X. Fan, O. Sinnen, N. Giacaman (2016). Towards an Event-Driven Programming Model for OpenMP. In Proc. of 9th Int. Workshop on Parallel Programming Models and Systems Software for High-End Computing (P2S2, in conjunction with ICPP 2016), Philadelphia, USA.(bib)

    Also, you can refer to the Pyjama Quick Reference Card and see the complete Pyjama directives and runtime funcitons.