我正在尝试使用多线程进行随机线性网络编码(RLNC)编码以提高性能。
但是,我遇到了性能问题,我的多线程解决方案速度慢,比当前的非线程版本慢得多。我暂停了atomic
访问m_completed
以及std :: mutex将元素插入到m_results
这会导致我的性能下降。但是,我不知道如何确认这一点。
在主线程completed()
的{{1}} - 循环中调用函数while
以获得更多信息,导致大量原子访问,但我不能找到一个没有原子或互斥锁的正确方法。你可以在下面找到代码。
所以,如果有人可以看到错误或指导我更好地做到这一点,我将非常感激。我已经花了1.5周的时间来弄清楚现在的错误,我的唯一想法是while(!encoder.completed()){}
或atomic
锁
std::mutex
答案 0 :(得分:1)
瓶颈可能不是对Completed()
的调用。
在x86上,来自字对齐uint32_t
的读取自动是原子操作,std::atomic
或不是std::atomic
。 uint32_t
在x86上对std::atomic<uint32_t> m_buffered[31]; std::atomic<uint_32t>& m_completed = m_buffered[15];
所做的唯一事情就是确保它是字对齐的,并且编译器不会重新排序或优化它。
紧密循环负载不是总线争用的原因。第一次读取时将出现高速缓存未命中,但后续加载将是高速缓存命中,直到通过从另一个线程写入地址使高速缓存无效。有一个警告 - 意外共享缓存行(&#34;虚假共享&#34;)。关于如何通过在原子的两侧切换到60字节未使用填充的数组来消除这种可能性的一个想法(仅使用中间的一个)。
int m_completed = 0; // no longer atomic
std::condition_variable cv;
// in main...(pseudocode)
lock (unique) m_mutex // the m_mutex from the class
while !Completed()
cv.wait(m_mutex)
// in thread (pseudocode)
bool toSignal = false;
lock guard m_mutex
this->m_result.insert(std::end(this->m_result),
std::begin(total_payload),
std::end(total_payload));
++m_completed;
toSignal = Completed();
if toSignal
cv.signalOne()
请记住,紧密循环会占用您的一个核心,除了查看其缓存之外什么都不做。这是浪费钱......;)这很可能是你问题的原因。您应该将代码更改为:
rescaleFactor
也可能是您的性能损失与互斥锁关键部分有关。这个关键部分可能比缓存未命中的时间长许多个数量级。我建议比较线程池中1个线程,2个线程和4个线程的时间。如果2个线程不比1个线程快,那么你的代码基本上是按顺序运行的。
如何衡量?当您不知道要优化什么时,分析工具很有用。我对它们没有很多经验,但我知道(至少有一些较旧的)在多线程方面会有点粗略。你也可以使用一个很好的老式计时器。如果你有合适的硬件,C ++ 11有一个high_resolution_clock可能在1微秒的分辨率。
最后,我看到了算法/标量优化的大量机会。预分配矢量而不是每次都这样做。使用指针或std :: move来避免不必要的深拷贝。预分配m_result并让线程写入特定的索引偏移量。