2015-03-27 5 views
12

Мы работали над нашим плеер проектом аудио на макинтоше и заметили, что потребление энергии было настолько высоко (около 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 
... 

(Мы используем монитор активности Мака (количество энергии) и центрального процессора средство профилирования для измерения потребления энергии.)

+5

Возможно, cv спины вместо того, чтобы спать в некоторых случаях? И, может быть, он делает «медленный» или «низкий уровень мощности» блокировки ... так или иначе? (Кстати, 3 единицы времени? Мы говорим «std :: condition_variable» здесь? Как там работает 3?) О, вы не публикуете фактический код, вы переписываете вручную и вводили неизвестное количество ошибок и пропуски. Пожалуйста, не делайте этого: пожалуйста, напишите код, который фактически воспроизводит то, что вас интересует. Это может включать в себя упрощение существующего кода: если вы поняли, что вызвало вашу интересную вещь, вы бы не спрашивали здесь! – Yakk

+2

Или, может быть, вы просто дожидаетесь с условием в сравнении с usleep? – Lol4t0

+0

в обоих случаях мы ждем 3 миллисекунды и повторим попытку. мы попробовали 4 миллисекунды, например, и заметили икоты –

ответ

1

Я могу ошибаться, но, насколько я понимаю, когда вы используете условную переменную реализовать ожидание поступления данных в буфер. Главное, что он делает, он ставит поток, который отображает эту переменную условия, спящий, пока связанный с ним сигнал не просыпает этот поток. Вот почему вы получаете меньше бодрствования и более эффективно используете ресурсы.

Вот ссылки на работы с потоками в Linux, где я читал об этом:

Может быть, это даст вам некоторое представление почему и как это происходит.

Снова я не совсем уверен, что я полностью прав, но мне кажется, что это правильное направление.

Извините за мой чистый английский.

+0

В случае с OP ничто никогда не пробуждает поток - он всегда спит до таймаута. – Arkadiy

0

Если вы хотите максимально снизить потребление энергии на Mac или iOS, по крайней мере, вы можете использовать dispatch_semaphore_t, чтобы подождать точно до тех пор, пока буфер не будет заполнен, или не передадите некоторый блок в код заполнения буфера.

Смежные вопросы