我为android(https://play.google.com/store/apps/details?id=cv.cvExperiments)编写了一个图像处理应用程序,其中包含一些用JNI包装的C ++代码。为了在多核处理器上获得一些加速,我用openmp注释了昂贵的循环"并行用于"指令。
问题是在x86上,我在4cores proc上获得了从x3到x5的一些加速,但是在Android上,激活OpenMP(使用-fopenmp)并没有在ARM 32位上提供任何加速,甚至减慢了代码的速度64位armv8 snapdragon 810。
我错过了什么吗?有没有人能够在android + arm上观察到与x86 cpus相比的加速?
互联网上有很多关于如何激活OpenMP的教程,但没有基准显示加速。任何指针?
我发现的唯一相关信息是armv8上OpenMP开销的基准,他们也发现了一些相当高的开销: https://wiki.linaro.org/WorkingGroups/Middleware/Graphics/GPGPU/Docs/OpenMPforARMv8PortAnalysis
谢谢, 马修
答案 0 :(得分:1)
Android上的多线程问题很可能与许多CPU的体系结构有关。 Snapdragon 810是low/high architecture,具有4个强核心和4个弱核心。
具体地说,810在big.LITTLE异构配置中采用了四个Cortex-A57和四个Cortex-A53内核,其中所有八个内核均可用于OS调度程序。
如果没有良好的工作程序池实现,则为平衡工作负载而产生的所有其他线程最终可能会成为性能低下的内核,据我估计,在繁重的SIMD计算中,速度大约是强内核的三倍。三星Exynos 9611)。
标记需要使用线程亲缘关系仅在强内核上创建额外的工作程序,或者每个工作负载都需要专门针对每个内核的能力进行定制;在这里,将16个块的工作分成3个核心,即3 + 3 + 3 + 3 + 1 + 1 + 1 + 1 + 1(快速核心的CPU ID为4..7)。
#pragma omp parallel num_threads(8)
{
auto tid = omp_get_thread_num();
uint8_t aff[sizeof(cpu_set_t)] = { 0x80 >> tid };
sched_setaffinity(0, 1, (cpu_set_t *)aff);
if (tid < 4) do_task(tid * 3, tid * 3 + 3);
else do_task(tid+8, tid+9);
}
使用OMP,使用这种方法,原本需要110毫秒的任务减少到30毫秒,而将工作交付到4个更好的内核只需约37毫秒。
在持续工作负载(例如实时信号处理)上,将工作拆分为内核数量的两倍似乎允许linux调度程序了解计算要求并将线程迁移到不同的内核,但这并不是万无一失的。 (8个内核等于16个块,平均每个快速内核将执行3个块,每个慢速内核将执行1个块。)
答案 1 :(得分:0)
在一个小基准(https://gist.github.com/matt-42/30b7caf73c345c28e55b7cfd82f5540c)之后,我可以观察到8核armv8上的x2加速。我想结论是,如果你可以通过OpenMP在桌面CPU上获得一些加速,那并不意味着你会在ARM CPU上看到类似的加速。