如何在OpenCL中累积向量?

时间:2017-02-10 10:12:04

标签: opencl opencl-c

我有一组循环运行的操作。

for(int i = 0; i < row; i++)
{
    sum += arr1[0] - arr2[0]
    sum += arr1[0] - arr2[0]
    sum += arr1[0] - arr2[0]
    sum += arr1[0] - arr2[0]

    arr1 += offset1;
    arr2 += offset2;
}

现在我正在尝试像这样对象进行矢量化

for(int i = 0; i < row; i++)
{
    convert_int4(vload4(0, arr1) - vload4(0, arr2));

    arr1 += offset1;
    arr2 += offset2;
}

但是如何在不使用循环的情况下在标量sum中累积结果向量?

我正在使用OpenCL 2.0。

3 个答案:

答案 0 :(得分:1)

该操作被称为&#34;减少&#34;似乎有一些信息here

在OpenCL中,似乎实现了特殊功能,其中一个work_group_reduce()可能会对您有所帮助:link

包含一些代码的演示文稿:link

答案 1 :(得分:1)

对于float2,float4等类似,最简单的版本可能是点积。 (从int转换为float可能很昂贵)

function getXMLValue(strXMLfile, XMLelement, infoID, XMLattrib)

    'Declare local variables
    Dim objXML, return_value
    return_value = null

    'Instantiate the XMLDOM Object that will hold the XML file.
    set objXML = Server.CreateObject("Microsoft.XMLDOM")

    'Turn off asyncronous file loading.
    objXML.async = false

    objXML.LoadXml(strXMLFile)
    objXML.setProperty "SelectionLanguage", "XPath" 

    if XMLelement = "date" then
        set return_value = objXML.selectSingleNode("date/@" & XMLattrib)

    elseif XMLelement = "id" then
        set return_value = objXML.selectSingleNode("subset/information[@id='" & infoID & "']/" & XMLattrib)

    elseif XMLelement = "page_title" then
        set return_value = objXML.selectSingleNode("page_title")

    elseif XMLelement = "date_stamp" then
        set return_value = objXML.selectSingleNode("date" & XMLvalue)

    elseif XMLelement = "timestamp" then
        set return_value = objXML.selectSingleNode("subset/information/[@id='" & infoID & "']/timestamp/@" & XMLattrib)

    end if  

    if not(isnull(return_value)) then
        getXMLvalue = return_value.text
    end if

    set return_value = nothing
    set objXML = nothing
end function

这等于

float4 v1=(float4 )(1,2,3,4);
float4 v2=(float4 )(5,6,7,8);

float sum=dot(v1-v2,(float4)(1,1,1,1));

如果有任何硬件支持,将它留给编译器的怜悯应该没问题。对于较大的矢量,特别是阵列,J.H.Bonarius的答案是要走的路。据我所知,只有CPU有这样的垂直和操作,GPU没有这个,但为了便于携带,dot product和work_group_reduce是实现可读性甚至性能的最简单方法。

Dot产品有额外的乘法因此总是不好。

答案 2 :(得分:1)

我找到了一个解决方案,这似乎是我能够解决问题的最接近的方式。

uint sum = 0;
uint16 S0, S1;

for(int i = 0; i < row; i++)
{
    S0 += convert_uint16(abs(vload16(0, arr1) - vload16(0, arr2)));
    S1 += convert_uint16(abs(vload16(1, arr1) - vload16(1, arr2)));

    arr1 += offset1;
    arr2 += offset2;
}

S0 = S0 + S1;
S0.s01234567 = S0.s01234567 + S0.s89abcdef;
S0.s0123 = S0.s0123 + S0.s4567;
S0.s01 = S0.s01 + S0.s23;
sum = S0.s0 + S0.s1;

OpenCL 2.0通过向量提供此功能,其中向量的元素可以连续替换为如上所示的加法运算。这可以支持最大为16的向量。较大的操作可以分成较小操作的因子。例如,为了在两个大小为32的向量之间添加差异的绝对值,我们可以执行以下操作:

<html>
  <head>
    <title>Title</title>
  </head>
  <body>
    <p>Hello {greeting}!</p>
    <table><tr>
      <td>Details:</td>
      <td>{details}</td>
    </tr></table>
  </body>
</html>