OpenHMPP (HMPP for Hybrid Multicore Parallel Programming) - programming standard for heterogeneous computing. Based on a set of compiler directives, standard is a programming model designed to handle hardware accelerators without the complexity associated with GPU programming. This approach based on directives has been implemented because they enable a loose relationship between an application code and the use of a hardware accelerator (HWA).
The OpenHMPP directive-based programming model offers a syntax to offload computations on hardware accelerators and to optimize data movement to/from the hardware memory.
The model is based on works initialized by CAPS (Compiler and Architecture for Embedded and Superscalar Processors), a common project from INRIA, CNRS, the University of Rennes 1 and the INSA of Rennes.
OpenHMPP is based on the concept of codelets, functions that can be remotely executed on HWAs.
A codelet has the following properties:
These properties ensure that a codelet RPC can be remotely executed by a HWA. This RPC and its associated data transfers can be asynchronous.
HMPP provides synchronous and asynchronous RPC. Implementation of asynchronous operation is hardware dependent.
HMPP considers two address spaces: the host processor one and the HWA memory.
The OpenHMPP directives may be seen as âÂÂmeta-informationâ added in the application source code. They are safe meta-information i.e. they do not change the original code behavior. They address the remote execution (RPC) of a function as well as the transfers of data to/from the HWA memory.
The table below introduces the OpenHMPP directives. OpenHMPP directives address different needs: some of them are dedicated to declarations and others are dedicated to the management of the execution.
One of the fundamental points of the HMPP approach is the concept of directives and their associated labels which makes it possible to expose a coherent structure on a whole set of directives disseminated in an application.
There are two kinds of labels:
In order to simplify the notations, regular expressions will be used to describe the syntax of the HMPP directives.
The color convention below is used for the description of syntax directives:
The general syntax of OpenHMPP directives is:
<span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">></span> [codelet_label]? <span style="color:#990000;">directive_type</span> [<span style="color:#339933;">,</span><span style="color:#990000;">directive_parameters</span>]* [<span style="color:#339933;">&</span>]
<span style="color:#339933;">!$hmpp <</span>grp_label<span style="color:#339933;">></span> [codelet_label]? <span style="color:#990000;">directive_type</span> [<span style="color:#339933;">,</span><span style="color:#990000;">directive_parameters</span>]* [<span style="color:#339933;">&</span>]
Where:
The parameters associated to a directive may be of different types. Below are the directive parameters defined in OpenHMPP:
A <code>codelet</code> directive declares a computation to be remotely executed on a hardware accelerator. For the <code>codelet</code> directive:
The syntax of the directive is:
<span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">></span> codelet_label <span style="color:#339933;">codelet</span> [<span style="color:#339933;">, version</span> = major.minor[.micro]?]? [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].io=</span>* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].size={</span>dimsize[,dimsize]*<span style="color:#339933;">}</span>]* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].const=true</span>]* [<span style="color:#339933;">, cond =</span> "expr"] [<span style="color:#339933;">, target=</span><span style="color:#990000;">target_name</span>[:<span style="color:#990000;">target_name</span>]*]
More than one codelet directive can be added to a function in order to specify different uses or different execution contexts. However, there can be only one codelet directive for a given call site label.
The <code>callsite</code> directive specifies how the use a codelet at a given point in the program.
The syntax of the directive is: <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">></span> codelet_label <span style="color:#339933;">callsite</span> [<span style="color:#339933;">, asynchronous</span>]? [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].size={</span>dimsize[,dimsize]*<span style="color:#339933;">}</span>]* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].advancedload=</span>* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].addr="</span>expr<span style="color:#339933;">"</span>]* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].noupdate=true</span>]*
An example is shown here :
In some cases, a specific management of the data throughout the application is required (CPU/GPU data movements optimization, shared variables...).
The <code>group</code> directive allows the declaration of a group of codelets. The parameters defined in this directive are applied to all codelets belonging to the group. The syntax of the directive is:
<span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">> group</span> [<span style="color:#339933;">, version =</span> <major>.<minor>[.<micro>]?]? [<span style="color:#339933;">, target =</span> <span style="color:#990000;">target_name</span>[:<span style="color:#990000;">target_name</span>]*]]? [<span style="color:#339933;">, cond = âÂÂ</span>expr<span style="color:#339933;">âÂÂ</span>]?
When using a HWA, the main bottleneck is often the data transfers between the HWA and the main processor.<br /> To limit the communication overhead, data transfers can be overlapped with successive executions of the same codelet by using the asynchronous property of the HWA.
The <code>allocate</code> directive locks the HWA and allocates the needed amount of memory. <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">> allocate</span> [<span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">].size={</span>dimsize[,dimsize]*<span style="color:#339933;">}</span>]*
The <code>release</code> directive specifies when to release the HWA for a group or a stand-alone codelet. <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">> release</span>
The <code>advancedload</code> directive prefetches data before the remote execution of the codelet.<br /> <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">></span> [codelet_label]? <span style="color:#339933;">advancedload</span> <span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">]</span> [<span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">].size={</span>dimsize[,dimsize]*<span style="color:#339933;">}</span>]* [<span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">].addr="</span>expr<span style="color:#339933;">"</span>]* [<span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">].section={</span>[<span style="color:#990000;">subscript_triplet</span><span style="color:#339933;">,</span>]+<span style="color:#339933;">}</span>]* [<span style="color:#339933;">,asynchronous</span>]
The <code>delegatedstore</code> directive is a synchronization barrier to wait for an asynchronous codelet execution to complete and to then download the results.<br /> <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">></span> [codelet_label]? <span style="color:#339933;">delegatedstore</span> <span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">]</span> [<span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">].addr="</span>expr<span style="color:#339933;">"</span>]* [<span style="color:#339933;">,args[</span>arg_items<span style="color:#339933;">].section={</span>[<span style="color:#990000;">subscript_triplet</span><span style="color:#339933;">,</span>]+<span style="color:#339933;">}</span>]*
The <code>synchronize</code> directive specifies to wait until the completion of an asynchronous callsite execution. For the synchronize directive, the codelet label is always mandatory and the group label is required if the codelet belongs to a group. <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">></span> codelet_label <span style="color:#339933;">synchronize</span>
In the following example, the device initialization, memory allocation and upload of the input data are done only once outside the loop and not in each iteration of the loop.
The <code>synchronize</code> directive allows to wait for the asynchronous execution of the codelet to complete before launching another iteration. Finally the <code>delegatedstore</code> directive outside the loop uploads the sgemm result.
Those directives map together all the arguments sharing the given name for all the group.
The types and dimensions of all mapped arguments must be identical.
The <code>map</code> directive maps several arguments on the device. <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">> map, args[</span>arg_items<span style="color:#339933;">]</span>
This directive is quite similar as the <code>map</code> directive except that the arguments to be mapped are directly specified by their name. The <code>mapbyname</code> directive is equivalent to multiple <code>map</code> directives. <span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">> mapbyname</span> [<span style="color:#339933;">,</span>variableName]+
The <code>resident</code> directive declares some variables as global within a group. Those variables can then be directly accessed from any codelet belonging to the group. This directive applies to the declaration statement just following it in the source code.
The syntax of this directive is:
<span style="color:#339933;">#pragma hmpp <</span>grp_label<span style="color:#339933;">> resident</span> [<span style="color:#339933;">, args[::</span>var_name<span style="color:#339933;">].io=</span>* [<span style="color:#339933;">, args[::</span>var_name<span style="color:#339933;">].size={</span>dimsize[,dimsize]*<span style="color:#339933;">}</span>]* [<span style="color:#339933;">, args[::</span>var_name<span style="color:#339933;">].addr="</span>expr<span style="color:#339933;">"</span>]* [<span style="color:#339933;">, args[::</span>var_name<span style="color:#339933;">].const=true</span>]*
The notation <code>::var_name</code> with the prefix <code>::</code>, indicates an application's variable declared as resident.
A region is a merge of the codelet/callsite directives. The goal is to avoid code restructuration to build the codelet. Therefore, all the attributes available for <code>codelet</code> or <code>callsite</code> directives can be used on <code>regions</code> directives.
In C language:
<span style="color:#339933;">#pragma hmpp [<</span>MyGroup<span style="color:#339933;">>] [</span>label<span style="color:#339933;">] region</span> [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].io=</span>* [<span style="color:#339933;">, cond = "</span>expr<span style="color:#339933;">"]</span>< [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].const=true</span>]* [<span style="color:#339933;">, target=</span><span style="color:#990000;">target_name</span>[<span style="color:#339933;">:</span><span style="color:#990000;">target_name</span>]*] [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].size={</span>dimsize[<span style="color:#339933;">,</span>dimsize]*<span style="color:#339933;">}</span>]* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].advancedload=</span>* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].addr="</span>expr<span style="color:#339933;">"</span>]* [<span style="color:#339933;">, args[</span>arg_items<span style="color:#339933;">].noupdate=true</span>]* [<span style="color:#339933;">, asynchronous</span>]? [<span style="color:#339933;">, private=[</span>arg_items<span style="color:#339933;">]</span>]* { C BLOCK STATEMENTS }
The OpenHMPP Open Standard is based on HMPP Version 2.3 (May 2009, CAPS entreprise).
The OpenHMPP directive-based programming model is implemented in:
OpenHMPP is used by HPC actors in Oil & Gas, Energy, Manufacturing, Finance, Education & Research.