如何在Nvidia Shield上正确计算Android RenderScript代码的时间

前端之家收集整理的这篇文章主要介绍了如何在Nvidia Shield上正确计算Android RenderScript代码的时间前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我在RenderScript中实现了一个小型CNN,并希望在不同硬件上分析性能.在我的Nexus 7上,时间是有意义的,但在NVIDIA Shield上他们没有.

CNN(LeNet)以驻留在队列中的9层实现,计算按顺序执行.每个层都是单独计时的.

这是一个例子:

conv1  pool1 conv2  pool2 resh1 ip1    relu1  ip2    softmax
nexus7 11.177 7.813 13.357 8.367 8.097 2.1    0.326  1.557  2.667
shield 13.219 1.024 1.567  1.081 0.988 14.588 13.323 14.318 40.347

时间的分布对于nexus来说是正确的,其中conv1和conv2(卷积层)占用大部分时间.但是在盾牌上,时间下降的方式超出了2-4层的合理范围,并且似乎朝着最后的方向聚集起来. softmax层是一个相对较小的工作,因此40ms太大了.我的计时方法必须是错误的,或者正在发生其他事情.

运行图层的代码如下所示:

double[] times = new double[layers.size()];
int layerindex = 0;
for (Layer a : layers) {

    double t = SystemClock.elapsedRealtime(); 
    //long t = System.currentTimeMillis(); // makes no difference

    blob = a.forward(blob); // here we call renderscript forEach_(),invoke_() etc

    //mRS.finish(); // makes no difference

    t = SystemClock.elapsedRealtime() - t; 
    //t = System.currentTimeMillis() - t; // makes no difference

    times[layerindex] += t; // later we take average etc

    layerindex++;
}

我的理解是,一旦forEach_()返回,该作业应该完成.无论如何,mRS.finish()应该提供最后的障碍.但从时代的角度来看,唯一合理的解释是,工作仍然在后台处理.

该应用程序非常简单,我只是从MainActivity运行测试并打印到logcat. Android Studio将应用程序构建为版本,并在通过USB连接的设备上运行.

(1)为RenderScript进程计时的正确方法是什么?
(2)当forEach_()返回时,脚本产生的线程是否可以保证完成?
(3)在我的测试应用程序中,我只是直接从MainActivity运行.这是一个问题(除了阻止UI线程并使应用程序无响应)?如果这会影响时间或导致奇怪,那么设置这样的测试应用程序的正确方法是什么?

解决方法

我自己在RenderScript中实现了CNN,正如你所解释的那样,如果你把它们作为一个不同的内核实现,它确实需要链接多个进程并为每个层调用forEach _ *()不同的时间.因此,我可以向您保证,返回的forEach调用并不能真正保证该过程已完成.从理论上讲,这只会调度内核,并且只要系统确定最佳请求,所有排队请求都会实际运行,特别是如果它们在平板电脑的GPU中处理完毕.

通常,绝对确保对真正运行的内核有某种控制的唯一方法是在层之间显式读取RS内核的输出,例如在该内核的输出分配对象上使用.copyTo(). .这会“强制”任何尚未运行的排队的RS作业(该层的输出分配依赖于该作业)在此时执行.当然,这可能会引入数据传输开销,并且您的时序不会完全准确 – 事实上,如果以这种方式计时,整个网络的执行时间肯定会低于各个层的总和.但据我所知,这是对链中各个内核计时的唯一可靠方法,它会为您提供一些反馈,以找出瓶颈所在,并更好地指导您的优化,如果这就是您所追求的.

猜你在找的Android相关文章