HMPP开放标准

HMPP用于异构多核并行编程。
OpenHMPP标准基于一组指令，是用于处理硬件加速器的编程模型，但又没有GPU编程的相关复杂性。这种基于指令的方法已经实现，因为他们使应用程序代码和硬件加速器使用之间形成松散关系。
本文涉及组成OpenHMPP标准的HMPP指令, 但并不处理指令的执行链接到指令执行。
简介.
OpenHMPP基于指令的编程模型提供了一种语法，有效地减轻硬件加速器上的计算，优化数据向/从硬件存储器移动。
模型基于 CAPS (编译器和超标量体系结构以及嵌入式处理器) 的初始化工作, 以及来自INRIA, CNRS, 雷恩第一大学和雷恩INSA的共同项目。
OpenHMPP标准概念.
OpenHMPP标准基于codelets的概念, 可以在硬件上远程执行。
OpenHMPP Codelet 概念.
codelet具有以下属性:
这些属性确保codelet RPC可以通过硬件远程执行。此RPC及其相关的数据传输可以是异步的。
Codelet RPCs.
HMPP提供同步和异步的RPC。异步操作的执行依赖于硬件。
HMPP 存储器模型.
HMPP考虑到两个地址空间: 一个主机处理器和硬件存储器。
指令概念.
OpenHMPP指令可能被视为“元信息” 添加到应用程序源代码。它们是安全的元信息，即不会改变原始代码的行为。它们处理函数的远程执行(RPC)，以及数据向/从硬件存储器传输。
下表介绍了OpenHMPP指令。OpenHMPP指令满足不同需求: 其中一些专门用于声明，其他用于执行的管理。
指令集的概念.
HMPP方法的基本点之一是指令的概念及其关联的标签，使它能够在分布于应用程序中的整个指令集上公开一个相干结构。
有两种类型的标签:
OpenHMPP指令语法.
为了简化符号, 正则表达式 将用于描述HMPP指令的语法。
下面的颜色通常用于描述指令的语法:
一般语法.
OpenHMPP指令的一般语法如下:
 #pragma hmpp &lt;grp_label&gt; [codelet_label]? directive_type [,directive_parameters]* [&amp;]
 !$hmpp &lt;grp_label&gt; [codelet_label]? directive_type [,directive_parameters]* [&amp;]
其中:
指令参数.
关联到一个指令的参数可能是不同类型。以下是 在HMPP中定义的指令参数:
OpenHMPP 指令.
声明和执行一个codelet的指令.
codelet指令声明在硬件加速器上远程执行计算。
codelet 指令:
该指令的语法是:
 #pragma hmpp &lt;grp_label&gt; codelet_label codelet 
 [, version = major.minor[.micro]?]?
 [, args[arg_items].io=out|inout*
 [, args[arg_items].size={dimsize[,dimsize]*}]*
 [, args[arg_items].const=true]*
 [, cond = "expr"]
 [, target=target_name[:target_name]*]
可以在一个函数中加入多个codelet指令，以便指定不同用途或不同执行文本。但是, 一个给定调用站点标签只能有一个codelet指令。
Callsite指令指定程序内的给定点如何使用一个codelet。
该指令的语法是:
 #pragma hmpp &lt;grp_label&gt; codelet_label callsite
 [, asynchronous]?
 [, args[arg_items].size={dimsize[,dimsize]*}]*
 [, args[arg_items].advancedload=false*
 [, args[arg_items].addr="expr"]*
 [, args[arg_items].noupdate=true]*
这里有一个例子:
/* declaration of the codelet */
 #pragma hmpp simple1 codelet, args[outv].io=inout, target=CUDA
 static void matvec(int sn, int sm, loat inv[sm], float inm[sn][sm], float *outv){
 int i, j;
 for (i = 0 ; i &lt; sm ; i++) {
 float temp = outv[i];
 for (j = 0 ; j &lt; sn ; j++) {
 temp += inv[j] * inm[i][ j];
 outv[i] = temp;
 
 int main(int argc, char **argv) {
 int n;
 
 /* codelet use */
 matvec(n, m, myinc, inm, myoutv);
某些情况下, 需要具体管理整个应用程序的数据(CPU/GPU 数据移动优化, 共享变量...)。
group指令允许声明一组codelets。 指令中定义的参数应用于所有属于该组的 codelets。
该指令的语法是:
 #pragma hmpp &lt;grp_label&gt; group 
 [, version = &lt;major&gt;.&lt;minor&gt;[.&lt;micro&gt;]?]? 
 [, target = target_name[:target_name]*]]? 
 [, cond = “expr”]?
数据传输指令可以优化通信开销.
硬件使用时的主要瓶颈通常是硬件和住处理器之间的数据传输。
要限制通信开销,可以通过使用硬件的异步属性，连续执行相同的codelet以重叠数据传输。
allocate指令锁定硬件，并分配所需的内存量。
release指令指定何时为一组或一个独立codelet释放硬件。 
 #pragma hmpp &lt;grp_label&gt; release
advancedload指令在codelet远程执行之前预取数据。
 ,args[arg_items]
 [,args[arg_items].size={dimsize[,dimsize]*}]*
 [,args[arg_items].addr="expr"]*
 [,args[arg_items].section={[subscript_triplet,]+}]*
 [,asynchronous]
delegatedstore指令是一个同步障，以等待一个异步codelet执行完成，然后下载结果。
 ,args[arg_items]
 [,args[arg_items].addr="expr"]*
 [,args[arg_items].section={[subscript_triplet,]+}]*
同步指令指定等待，直到一个异步callsite执行完成。对于同步指令, codelet 标签始终是强制性的，并且若是codelet属于一个组，需要有组标签。
在下面的例子中，完成设备初始化，内存分配和输入数据的上载在循环外只有一次，而不是每次循环迭代。
同步指令允许在启动另一个迭代之前等待codelet的异步执行的完成。最后在循环外delegatedstore指令将上载sgemm结果。
int main(int argc, char **argv) {
 #pragma hmpp sgemm advancedload, args[vin1;vin2;vout], args[m,n,k,alpha,beta]
 for ( j = 0 ; j &lt; 2 ; j ++) {
 #pragma hmpp sgemm callsite, asynchronous, args[vin1;vin2;vout].advancedload=true, args[m,n,k,alpha,beta].advancedload=true
 sgemm (size, size, size, alpha, vin1, vin2, beta, vout);
 #pragma hmpp sgemm synchronize
 
 #pragma hmpp sgemm delegatedstore, args[vout]
 #pragma hmpp sgemm release
Codelets之间共享数据.
这些指令共同映射所有参数共享所有组的给定名称。
所有映射参数的类型和尺寸必须是相同的。
map指令映射设备上的几个参数。
此指令除了参数按其名称直接指定映射之外，与map指令很类似。 mapbyname 指令相当于多映射指令。
 #pragma hmpp &lt;grp_label&gt; mapbyname [,variableName]+
全局变量.
Resident指令声明某些变量在一个组内为全局变量。 然后可以从任何属于组的codelet中直接访问这些变量。此指令应用于源代码中在其之后的声明语句。
此指令的语法是:
 #pragma hmpp &lt;grp_label&gt; resident 
 [, args[::var_name].io=out|inout*
 [, args[::var_name].size={dimsize[,dimsize]*}]*
 [, args[::var_name].addr="expr"]*
 [, args[::var_name].const=true]*
符号::var_name 以::为前缀, 表示一个应用程序的变量声明为resident。
加速区.
codelet/callsite指令合并为一个区域。目的是避免代码重构中构建codelet。 因此，所有codelet或callsite指令可用属性都可以用于regions指令。
在C语言中:
 #pragma hmpp [&lt;MyGroup&gt;] [label] region 
 [, args[arg_items].io=out|inout*
 [, cond = "expr"]&lt;
 [, args[arg_items].const=true]*
 [, target=target_name[:target_name]*]
 [, args[arg_items].size={dimsize[,dimsize]*}]*
 [, args[arg_items].advancedload=false*
 [, args[arg_items].addr="expr"]*
 [, args[arg_items].noupdate=true]*
 [, asynchronous]?
 [, private=[arg_items]]*
 C BLOCK STATEMENTS
实现.
HMPP开放标准基于HMPP 2.3版本(2009年5月, CAPS 公司).
HMPP基于指令的编程模型已经实现如下:
此外，HMPP开放标准用于石油和天然气，能源，制造业，金融，教育及研究领域的高性能计算，让开发人员使用大部分多核处理器，同时保留其遗留资源。