为什么条件变量会固定我们的功耗



我们在mac上进行音频播放器项目时,注意到功耗非常高(大约是谷歌chrome处理相同工作负载的7倍)

我使用了xcode的能量分析工具,其中一个问题是我们有太多的cpu唤醒开销。

根据xcode:

每次CPU从空闲状态唤醒时,都会产生能量损失。如果唤醒很高,而每次唤醒的CPU利用率很低,那么您应该考虑批处理工作。

我们已经将问题缩小到一个usleep函数调用。

在我们的代码中,音频解码器是一个生产者,它产生音频数据并将它们插入消费者——音频播放器。我们的音频播放器基于OpenAL,它有一个音频数据缓冲区。

因为音频播放器可能比制作人慢,所以在向音频播放器提供新的音频数据之前,我们总是检查缓冲区的可用性。如果没有可用的缓冲区,我们将休眠一段时间,然后重试。所以代码看起来像:

void playAudioBuffer(Data *data)
{
    while(no buffer is available)
    {
         usleep()
    }
    process data.
}

知道usleep是个问题,我们做的第一件事就是简单地删除usleep()。(因为OpenAL似乎不提供回调或任何其他方式,轮询似乎是唯一的选择。)在这样做之后,我们成功地将功耗降低了一半。

然后,昨天,我们尝试了

for(int i =0; i<attempts; ++i)
{
    std::unique_lock<std::mutex> lk(m);
    cv.wait_for(lk, 3, []{
                            available = checkBufferAvailable(); 
                            return available;
                         })
    if (available)
    {
         process buf;
    }
 }

这是我们偶然尝试的一个实验。这对我们来说并没有真正的意义,因为从逻辑上讲,它执行相同的等待。条件变量的使用是不正确的,因为变量"available"只能由一个线程访问。但它实际上降低了我们90%的能耗,线程的cpu使用量下降了很多。现在我们比铬更好。但是,条件变量的实现方式与下面的代码有何不同?为什么它能为我们节省电力?

mutex lock;
while(condition is false)
{
    mutex unlock;
    usleep();
    mutex lock;
}
...
mutex unlock
...

(我们使用mac的活动监视器(能量数)和cpu使用情况分析工具来测量能量消耗。)

我可能错了,但据我所知,当您使用条件变量来实现等待缓冲区数据收入时。它所做的主要事情是,让呈现这个条件变量的线程进入睡眠状态,直到与它相关的信号唤醒这个线程。这就是为什么您可以减少唤醒开销并更有效地使用资源的原因。

以下是在Linux中使用线程的链接,我在这里读到了它:

  • POSIX螺纹第1部分
  • POSIX螺纹第2部分
  • POSIX螺纹第3部分

也许这会让你了解为什么以及如何发生。

再说一遍,我不完全确定自己是否完全正确,但在我看来,这是一个正确的方向。

对不起,我的英语很纯正。

如果你想在Mac或iOS上尽可能降低能耗,至少你可以使用dispatch_semaphore_t来等待缓冲区满,或者将一些块传递给缓冲区填充代码。

相关内容

  • 没有找到相关文章

最新更新