当前位置: 首页 > 知识库问答 >
问题:

Aparapi GPU执行速度比CPU慢

法子昂
2023-03-14

我正在尝试测试Aparapi的性能。我看到过一些博客,其中的结果显示,Aparapi确实在做数据并行操作的同时提高了性能。

但我在测试中没有看到这一点。这里是我所做的,我写了两个程序,一个使用Aparapi,另一个使用普通循环。

方案1:在Aparapi

import com.amd.aparapi.Kernel;
import com.amd.aparapi.Range;

public class App 
{
    public static void main( String[] args )
    {
        final int size = 50000000;

        final float[] a = new float[size];
        final float[] b = new float[size];

        for (int i = 0; i < size; i++) {
           a[i] = (float) (Math.random() * 100);
           b[i] = (float) (Math.random() * 100);
        }

        final float[] sum = new float[size];

        Kernel kernel = new Kernel(){
           @Override public void run() {
              int gid = getGlobalId();
              sum[gid] = a[gid] + b[gid];
           }
        };
        long t1 = System.currentTimeMillis();
        kernel.execute(Range.create(size));
        long t2 = System.currentTimeMillis();
        System.out.println("Execution mode = "+kernel.getExecutionMode());
        kernel.dispose();
        System.out.println(t2-t1);
    }
}

程序2:使用循环

public class App2 {

    public static void main(String[] args) {

        final int size = 50000000;

        final float[] a = new float[size];
        final float[] b = new float[size];

        for (int i = 0; i < size; i++) {
           a[i] = (float) (Math.random() * 100);
           b[i] = (float) (Math.random() * 100);
        }

        final float[] sum = new float[size];
        long t1 = System.currentTimeMillis();
        for(int i=0;i<size;i++) {
            sum[i]=a[i]+b[i];
        }

        long t2 = System.currentTimeMillis();
        System.out.println(t2-t1);

    }
}

程序1需要大约330ms,而程序2只需要大约55ms。我是不是做错什么了?我在Aparpai程序中打印出了执行模式,它打印出的执行模式是GPU

共有1个答案

酆奇文
2023-03-14

您没有做错任何事情--execpt用于基准本身。

基准测试总是很棘手的,特别是在涉及JIT的情况下(如Java),以及对用户隐藏了许多重要细节的库(如Aparapi)。而且在这两种情况下,您至少应该多次执行您想要基准测试的代码段。

对于Java版本,由于JIT的介入,当循环本身被多次执行时,一次执行循环的计算时间可能会减少。还有许多额外的注意事项需要考虑--有关详细信息,您应该参考这个答案。在这个简单的测试中,JIT的效果可能并不明显,但在更现实或更复杂的场景中,这将会产生影响。Anyhow:重复循环10次时,在我的机器上单次执行循环的时间大约是70毫秒。

对于Aparapi版本,注释中已经提到了可能的GPU初始化。在这里,这确实是主要的问题:当运行内核10次时,我的机器上的计时是

1248
72
72
72
73
71
72
73
72
72

您会看到初始调用会导致所有开销。原因是,在第一次调用kernel#execute()时,它必须进行所有初始化(基本上是将字节码转换为OpenCL,编译OpenCL代码等)。在KernelRunner类的文档中也提到了这一点:

由于调用kernel.execute()而懒洋洋地创建了kernelrunner

这样做的结果--第一次执行的延迟相对较大--导致了Aparapi邮件列表中的这个问题:一种急切地创建KernelRunner的方法。建议的唯一解决方法是创建一个“初始化调用”,如

kernel.execute(Range.create(1));

没有一个真实的工作量,只为触发整个设置,使后续调用快速。(这也适用于您的示例)。

您可能已经注意到,即使在初始化之后,Aparapi版本仍然不比纯Java版本快。其原因是,像这样的简单向量加法的任务是内存限制的--关于细节,您可以参考这个答案,它解释了这个术语和GPU编程的一些问题。

对于您可能从GPU中获益的情况来说,作为一个过度提示性的示例,您可能想要修改测试,以便创建一个人为的计算约束任务:当您更改内核以涉及一些昂贵的三角函数时,如下所示

Kernel kernel = new Kernel() {
    @Override
    public void run() {
        int gid = getGlobalId();
        sum[gid] = (float)(Math.cos(Math.sin(a[gid])) + Math.sin(Math.cos(b[gid])));
    }
};

以及相应的普通Java循环版本,如下所示

for (int i = 0; i < size; i++) {
    sum[i] = (float)(Math.cos(Math.sin(a[i])) + Math.sin(Math.cos(b[i])));;
}

然后你就会看到一个不同。在我的机器上(GeForce 970 GPU vs.AMD K10 CPU),Aparapi版本的计时大约是140毫秒,而普通Java版本的计时是惊人的12000毫秒--这是通过Aparapi加快了近90!

还要注意,即使在CPU模式下,Aparapi也可能比普通Java提供优势。在我的机器上,在CPU模式下,Aparapi只需要2300毫秒,因为它仍然使用Java线程池并行化执行。

 类似资料:
  • 问题内容: 为了找到两个数据库之间的所有更改,我将pk上的表联接在一起,并使用date_modified字段选择最新记录。由于表具有相同的架构,因此将使用提高的性能。我想用重写它,但是我不确定在每种情况下for的实现是否都可以执行。希望有人对何时使用有更多的技术说明。 问题答案: 任何人都无法告诉您,它永远或永远不会超过同等产品。无论您如何编写意图,优化器都会选择合适的执行计划。 就是说,这是我的

  • 我最近在我的笔记本电脑上安装了GPU tenstorflow、CUDA和cuDNN,使用本教程使用我的GPU训练我的模型。我的笔记本电脑是联想ideapad 510,处理器=i5-7代,GPU=GForce 940MX(4GB)。根据教程,我安装并配置了使用GPU所需的所有更改。 每个epoc只需6秒钟就可以编译60000张图像。在表中,我可以看到我的GPU内存使用量是19MiB。在本教程中,他的

  • 我在程序(计时器类)中使用scheduleAtFixedRate方法。它每秒钟运行一次,但有时这种方法会变得非常快(每秒执行3-4次)。 然而,我在网上做了一些研究,发现了这个: 复制自android开发者页面: 对于固定速率执行,任务每次连续运行的开始时间都是计划的,而不考虑上一次运行的时间。如果延迟阻止计时器按时启动任务,则这可能会导致一系列串接运行(一个接一个地启动)。 我需要固定的计时器。

  • 我最近用Java写了一个计算密集型算法,然后把它翻译成C++。令我吃惊的是,C++的执行速度要慢得多。我现在已经编写了一个更短的Java测试程序,以及一个相应的C++程序-参见下面。我的原始代码具有大量的数组访问功能,测试代码也是如此。C++的执行时间要长5.5倍(请参阅每个程序末尾的注释)。 以下1st21条评论后的结论... null null Java代码: C++代码:

  • 问题内容: 我一直在使用HTMLUnit。非常适合我的要求。但这似乎非常缓慢。例如:我已经使用HTMLUnit自动化了以下场景 代码: 它运作良好100%。但是需要3分41秒 我想执行缓慢的原因是要验证页面上的每个元素。 我的问题是如何减少HTMLUnit的执行时间?有什么方法可以禁用网页上的验证。 提前致谢! 问题答案: 对于当前的htmlUnit 2.13,设置选项与maxmax提供的设置略有

  • 比赛速度功能有助于您保持稳定配速,并在设定距离内达到您的目标时间。定义某段距离的目标时间 - 例如将 10 公里跑步的目标时间设定为 45 分钟,并跟踪对比实际用时与这个预设目标的差距。 您可以在手表上设置比赛速度,或者可以在 Flow 网络服务或应用程序中设置比赛速度目标,并同步至手表。 如果您已计划好当天的比赛速度目标,手表会在进入训练准备模式时建议您启动该目标。 在手表上创建比赛速度目标 您