我们正在使用Mac上的音频播放器项目,并注意到电源使用率非常高(大约是Google Chrome执行相同工作负载的7倍。)
我使用了xcode的能量分析工具,其中一个问题是我们有太多的cpu-wake开销。
根据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使用情况分析工具来测量能耗。)
答案 0 :(得分:1)
我可能错了,但据我所知,当您使用条件变量来实现等待缓冲区数据收入时。它做的主要是,它使渲染这个条件变量的线程休眠,直到与它相关的信号唤醒这个线程。这就是为什么您获得较少的唤醒开销并更有效地使用资源的原因。
以下是在Linux中使用线程的链接,我在其中阅读了它:
这可能会让你理解为什么以及如何发生。
我再也不能确定我是完全正确的,但在我看来,这似乎是一个正确的方向。
抱歉我的纯英语。
答案 1 :(得分:0)
如果您想在Mac或iOS上尽可能地降低能耗,至少可以使用dispatch_semaphore_t等待缓冲区已满,或者将一些块传递给缓冲区填充代码。