【问题标题】:OpenCL - Array values being overwrittenOpenCL - 数组值被覆盖
【发布时间】:2016-05-17 14:15:03
【问题描述】:

我遇到了一个问题,我以前的数组元素被新值覆盖。

代码试图做什么

我最初有一个包含 100 个元素的数组(全部来自正弦函数,这是我的输入)。它本质上是充当 FIFO 缓冲区,并在将新输入推入 FIFO 时计算数组的平均值。我这样做的原因是因为我正在尝试实现移动平均过滤器。

但是,输出往往会覆盖以前的值。 例如,如果 FIFO 缓冲区的第一个元素是 1(这意味着当前缓冲区的其余部分包含 0),则位置 0 处的输出数组将具有 0.01 作为值。下一次,如果下一个输入值为 0.9,则索引 1 处的输出值为 (0.01+0.009)。但这是索引 0 的值也被覆盖为与索引 1 相同的值的地方。

我决定用 java 编写相同的代码,它工作得非常好。如果有人能解决这个问题,我将不胜感激。

kernel void lowpass(__global float *Array, __global float *Output) { 
    float fifo[100]; 
    int queueIn; 
    float tempVal; 
    queueIn = 0; 
    int idx = get_global_id(0); 
    Output[idx] = 0; 
    fifo[idx] = 0; 

    for(int i = queueIn; i < 3; i++){ 
        fifo[i] = Array[i]; 
        tempVal = (float)0; 
        for(int j = 0; j < 3; j++){ 
             tempVal = (float) (fifo[j]*(.01) + tempVal);
        } 
        Output[queueIn] = tempVal; 
        queueIn = queueIn + 1; 
    }
}

请注意,出于调试目的,我将 for 循环设置为 3。从跟踪代码来看,它不应该这样做。但话又说回来,我可能会遗漏一些小东西。

**此外,出于调试原因,我已经删除了很多变量,例如 queueIn,我只需要使数组不会覆盖以前的值。

cmd 输出示例

Java 代码

public static void main(String[] args) {
    // TODO Auto-generated method stub

    //Input,output and fifo arrays
    float [] fifo = new float[100];
    float [] input = new float[100];
    float [] output = new float[100];

    //temporary value to hold computed result
    float temp = 0;

    //initialize array values to 0
    for(int i =0;i<100;i++){
        fifo[i] = 0;
        input[i] = 0;
        output[i] = 0;
    }

    //I know this produces a constant result, but its just 
    //proof of concept. this array will have values of .707 throughout it
    for(int i =0;i<100;i++){
        temp = (float) Math.sin(Math.toRadians(45));
        input[i] = temp;
    }   

    int queueIn; 
    float tempVal; 
    tempVal=0; 
    queueIn = 0; 
    //Insert one value at a time into the fifo buffer (first for loop)
    for(int i = queueIn; i < 100; i++){ 
        fifo[i] = input[i]; 

        //reset to 0 so it can reaccumilate
        tempVal = 0;

        //accumilate the values in the array multiplied by a coefficient one value in 
        //the array changes every time the first for loop executes.
        for(int j = 0; j < 100; j++){ 
            tempVal = (float) (fifo[j]*(0.01) + tempVal);

        } 
        //store the value in the current index of the output array. 
        output[queueIn] = tempVal; 
        queueIn = queueIn + 1;
    }

    //verify results
    for(int i =0;i<100;i++){
        System.out.println(output[i]);
    }

}

【问题讨论】:

  • 你说它在java中工作。你可以发布java代码吗?不确定您要做什么。
  • 刚刚发布了代码。主要部分是这个,我有两个 for 循环。第一个 for 循环每次将一个元素插入 FIFO 循环缓冲区。下一个 for 循环在元素添加后开始,它重新计算整个数组的平均值乘以一个系数。最终目标是为信号实现移动平均滤波器。
  • 我希望 1.0/4 出现在 (fifo[j]*(.01) + tempVal); 中,而不是 0.01
  • Java 使用output[queueIn] = tempVal;,C 使用Output[i] = tempVal;。为什么会有差异?
  • 完全一样,我只是修复了它以使其保持一致。它仍然给我同样的问题,输出被多次替换。在我尝试在没有 queueIn 变量(在 C 中)的情况下对其进行调试后,我忘记了将值改回来。

标签: c arrays opencl


【解决方案1】:

内核的第一部分被实现为作为 NDRange 运行,而主要部分是为 Task 完成计算(作为单个工作项运行),因此每个工作项都覆盖了值。

根据您的 Java 实现,NDRange 内核实现应该是这样的:

kernel void lowpass(__global float *Array, __global float *Output) {
    int idx = get_global_id(0);

    float tempVal = 0.0f;
    for(int j = 0; j < idx+1; j++){ 
        tempVal += Array[j] * 0.01f;
    }

    Output[idx] = tempVal;
}

【讨论】:

  • 谢谢!它工作得很好。对于“为作为 NDRange 运行而实现”的意思有点困惑。
  • NDRange 意味着运行许多工作项,并且在内核开始时您使用了int idx = get_global_id(0);,这表明内核是 NDRange 类型。对于单个工作项内核,您不需要它。
  • 那么是否可以在没有 NDRange 类型的情况下编写相同的函数?我尝试删除 get_global_id(0) 但它仍然做同样的事情。
  • 不,您必须重新实现内核以使其看起来更像在 CPU 上,但通常在 GPU 上运行速度非常慢,除非您想在 CPU 上运行它,然后您可以尝试一下。跨度>
猜你喜欢
  • 1970-01-01
  • 2012-05-09
  • 2018-01-29
  • 1970-01-01
  • 2015-11-08
  • 2016-12-27
  • 2013-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多