我正在用C ++编写一个程序来执行特定系统的模拟。对于每个时间步,执行的最大部分是由单个循环占用。幸运的是,这是非常平行的,所以我决定使用Boost Threads并行化它(我在2核机器上运行)。我期望加速接近串行版本的2倍,因为没有锁定。但是我发现根本没有加速。
我按如下方式实现了循环的并行版本:
然后每个线程执行以下操作:
主线程等待作业完成障碍。
我使用这种方法,因为它应该提供良好的负载平衡(因为每次计算可能需要不同的时间量)。我真的很好奇可能导致这种放缓的原因。我总是读到原子变量很快,但现在我开始怀疑它们是否有性能成本。
如果有人想要寻找什么或任何提示,我会非常感激。我一直在猛烈抨击它一个星期,并且剖析并没有透露太多。
编辑:问题解决了! 我将详细说明我是如何解决这个问题的。我再次使用gprof,但这次编译时没有优化标志(-O3)。然后,分析器立即表明我在函数中花费了不可思议的时间,该函数对每个单独的粒子执行计算:远远超过串行版本。
此功能是虚拟的,可以多态访问。我改变了代码直接访问它,而不是通过vtable和voila'并行版本产生了近2的加速!串行版本的相同更改几乎没有效果。
我不确定为什么会这样,如果有人知道的话会感兴趣!
感谢所有的海报。你们在某种程度上都有所帮助,接受一个答案是非常困难的。
答案 0 :(得分:2)
对该粒子执行计算,将结果存储在单独的数组中
计算有多重?
老实说......看起来你在谈论的是一个错误。
答案 1 :(得分:1)
profiling has not revealed much
目前尚不清楚。我有在HP-UX上分析多线程应用程序的经验,并且他们的分析器表示每个函数运行的时间百分比。因此,如果您的函数中有一个或几个争用点,则应用程序在这些函数中花费的时间会增加。在我的情况下,pthread_mutex_unlock()
显着增加。当我更改代码时,它变得更快。
所以你可以在这里发布一个线程和两个/四个线程的相同统计信息。和每次测试中的计算次数。
另外,我建议您(如果可能的话)在锁定互斥锁的全局函数上设置断点。您可能会发现算法中的某个位置偶然会锁定全局互斥锁。
答案 2 :(得分:1)
你的语言有点透露:
等待xxx
这可能是你的问题。
另外,再次添加到单个结果队列时会变慢 - 如果可能,您可以仅在处理结束时将结果添加到单个队列中。主线程不应该等待,每次更新后都要检查全局计数器
我将添加您在最后记录的性能计数器,而不是分析。您可能会将它们置于条件编译错误中,因此它们不会添加到您的生产代码中。
答案 3 :(得分:0)
你说剖析没有透露太多,而且(遗憾地)是典型的。
这就是我要做的事情:
返回单线程。
使用this profiling technique that works in any language and environment尽可能快地创建单个线程。原因是剖析器(大多数但不是全部)只擅长测量变化,而不是精确定位你应该修复的东西。
然后返回1-thread-per-core,再次执行该过程。如果您发现一个线程或另一个线程在进程间通信上花费了很多时间,那么您需要重新进行操作。
答案 4 :(得分:0)
我可以建议您可以更轻松地找到OpenMP这种并行吗?因为你只是想让循环并行,你真的不想明确地使用线程,这正是OMP真正有效的事情。
无论如何都值得一试。