Мы работали над нашим плеер проектом аудио на макинтоше и заметили, что потребление энергии было настолько высоко (около 7x, что в Google Chrome делает ту же нагрузку.)Почему условная переменная фиксирует потребление энергии?
Я использовал инструмент энергии профилирования Xcode, одной из проблем была у нас было слишком много cpu-wake overhead.
По Xcode:
Каждый раз, когда процессор выходит из режима холостого хода, есть понесены энергии штраф. Если будильники высоки, а загрузка процессора на один такт низка, вам следует рассмотреть возможность пакетной работы.
Мы сузили проблему до вызова функции управления игрой.
В нашем коде аудиодекодер является производителем, который производит аудиоданные и вставляет их в потребитель - аудиоплеер. Наш аудиоплеер основан на 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;
}
}
Это эксперимент мы пытались случайно. Это не имеет для нас никакого смысла, поскольку логически он выполняет одно и то же ожидание. И использование условной переменной неверно, потому что для переменной «доступно» доступен только один поток. Но это фактически сократило потребление энергии на 90%, использование процессора в потоке сильно упало. Теперь мы лучше, чем хром. Но как условная переменная реализована иначе, чем следующий код? Почему это спасает нас от власти?
mutex lock;
while(condition is false)
{
mutex unlock;
usleep();
mutex lock;
}
...
mutex unlock
...
(Мы используем монитор активности Мака (количество энергии) и центрального процессора средство профилирования для измерения потребления энергии.)
Возможно, cv спины вместо того, чтобы спать в некоторых случаях? И, может быть, он делает «медленный» или «низкий уровень мощности» блокировки ... так или иначе? (Кстати, 3 единицы времени? Мы говорим «std :: condition_variable» здесь? Как там работает 3?) О, вы не публикуете фактический код, вы переписываете вручную и вводили неизвестное количество ошибок и пропуски. Пожалуйста, не делайте этого: пожалуйста, напишите код, который фактически воспроизводит то, что вас интересует. Это может включать в себя упрощение существующего кода: если вы поняли, что вызвало вашу интересную вещь, вы бы не спрашивали здесь! – Yakk
Или, может быть, вы просто дожидаетесь с условием в сравнении с usleep? – Lol4t0
в обоих случаях мы ждем 3 миллисекунды и повторим попытку. мы попробовали 4 миллисекунды, например, и заметили икоты –