Как создавать «зеленый» код

Что такое энерго-эффективность в применении к мобильным платформам? Простыми словами это возможность сделать больше, затратив при этом меньше энергии.


Каждому пользователю хотелось бы как можно реже заряжать свое мобильное устройство, будь то смартфон, нетбук, ультрабук. Возможно, когда-нибудь наступит момент, когда устройство нужно будет зарядить всего один раз, после его покупки и пользоваться до тех пор пока оно не надоест или морально не устареет.

Если рассмотреть укрупненую модель любой мобильной платформы то она состоит и 3-х основных частей.






Аккумулятор






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






Железо






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






Софт






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


Как именно софт влияет на потребление энергии? Если в двух словах - он не дает железу "спать".


Рассмотрим одного из крупных потребителей энергии в системе - процессор.


Процессор может управлять своим энергопотреблением с помощью, так называемых, C-State. Для тех, кто не знаком с этими режимами, привожу короткую справку:




  • С0 - рабочее состояние процессора, подразделяется на различные P-States.

  • C1 - состояние, когда процессор ничего не делает, но готов приступить к работе, правда с небольшой задержкой. Многие процессоры имеют различные вариации этого состояния.

  • С2 - почти тоже самое, что и С1, но в этом состоянии процессор потребляет меньше энергии, и имеет большую задержку для перехода в рабочее состояние.

  • С3 - состояние "сна", переходя в это состояние процессор очищает кэш второго уровня. Характеризуется меньшим энергопотреблением, и более долгим временем перехода в рабочее состояние.

  • ...и так далее в зависимости от процессора.


Для того чтобы было более наглядно приведу иллюстрацию:



Самый энерго-эффективный вариант - процессор всегда спит. Значит самая эффективная, в плане энергозатрат программа, это та программа, которая не запущена и его не "будит". Она не производит никаких действий, и вообще ничего не потребляет. Но такой софт никому не нужен, программа должна делать что-то полезное. Компромисное решение - программа, которая не делает ничего тогда когда не должна ничего делать ("будит" только по нужде), и если делает что-то, то делает это максимально быстро.

Особенно это касается программ, которые выполняют какие-либо действия в фоновом режиме. Эти программы должны спать всегда и просыпаться только при наступлении какого-либо события.





События рулят или Event-driven подход





Приведу пример "неправильного" кода (к сожалению, такой подход к написанию кода используется гораздо чаще, чем вы думаете). Данный пример кода служит для получения и данных из сокета, например, в каком-нибудь серверном приложении.




while(true)

{

	// Получаем данные

	result = recv(serverSocket, buffer, bufferLen, 0);


	// Обработка полученных данных	

	if(result != 0)

	{

		HandleData(buffer);

	}


	// Спим секунду и повторяем

	Sleep(1000);

}



Что же здесь "неправильного"? Есть данные или нет данных, код будет "будить" процессор каждые 1000 мс. Поведение кода напоминает осла из Шрека: "Уже приехали? А теперь приехали? А сейчас приехали?".


"Правильный" код, для данной задачи, не будет ни кого спрашивать, он уснет у будет ждать когда разбудят его. Для этого, во многих операционных системах, существуют объекты синхронизации, такие как события. С учетом сказанного код должен выглядеть так (код не полный, опущена обработка ошибок и кодов возврата, моя задача просто проиллюстрировать принцип):




WSANETWORKEVENTS NetworkEvents;

WSAEVENT	 wsaSocketEvent;

wsaSocketEvent = WSACreateEvent();


WSAEventSelect(serverSocket, wsaSocketEvent, FD_READ|FD_CLOSE);


while(true)

{

	// Ждем наступления одного из событий - получения данных или закрытия сокета

	WaitForSingleObject(wsaSocketEvent, INFINITE);


	// Что произошло?

	WSAEnumNetworkEvents(m_hServerSocket, wsaSocketEvent, &NetworkEvents);


	// Пришли новые данные

	if(NetworkEvents.lNetworkEvents & FD_READ)

	{

		// Читаем, обрабатываем

		WSARecvFrom(serverSocket, &buffer, ...);

	}

}



В чем прелесть примера выше? Он будет спать тогда, когда ему нечего делать.





Таймеры, будильники нашего кода





Иногда без таймеров не обойтись, примеров масса - проигрывание аудио, видео, анимация.


Немного о таймерах. Интервал системного таймера Windows, по умолчанию, равен 15,6 мс. Что это означает для программ? Допустим вы хотите, чтобы выше приложение выполняло какое-то действие каждые 40 мс. Проходит первый интервал в 15,6 мс, слишком мало, проходит второй 31,1, опять рано, третий 46,8 - попали, таймер сработает. В большинстве случаев лишние 6,8 мс не имеют значения.


Так же прямое влияние на Sleep, если вы вызовете Sleep(1), при установленном интервале в 15,6 мс, то спать код будет не 1 мс, а все 15,6 мс.


Но если дело касается проигрывания видео - тогда это поведение не приемлемо. В этих случаях разработчик может изменить дискретность системного таймера вызвав функцию из Windows Multimedia API - timeBeginPeriod. Данная функция позволяет изменить период таймера вплоть до 1мс. Для кода это хорошо, но сильно сокращает жизнь батареи (вплоть до 25%).


Как найти компромисс? Все просто изменяйте период системного таймера только тогда, когда это действительно необходимо. Например, если вы разрабатываете приложение, использующее анимацию и вам нужна меньшая дискретность таймера меняйте таймер тогда, когда анимация отображается и происходит, и возвращайте если, например, окно свернуто или анимация остановлена.


С точки зрения пользователя иногда, чтобы понять как продлить жизнь от батареи будет интересна утилита Powercfg. С ее помощью можно узнать какое-то приложение изменило период системого таймера, значение периода системного таймера, информацию о проблемах драйверов, не позволяющих переводить "железо" в режим низкого энерго потребления и т.д.





Объединение таймеров





В Windows 7 появилась замечательная возможность объединять таймеры. Что это такое и как это работает представлено на рисунке ниже:







Т.е. Windows "подстраивает" таймеры приложений таким образом, чтобы они совпадали со срабатываниями таймера самой операционной системы.




Для того, чтобы использовать эту возможность необходимо вызвать





BOOL WINAPI
SetWaitableTimerEx(
__in HANDLE hTimer,
__in const LARGE_INTEGER *lpDueTime,
__in LONG lPeriod,
__in_opt PTIMERAPCROUTINE pfnCompletionRoutine,
__in_opt LPVOID lpArgToCompletionRoutine,
__in_opt PREASON_CONTEXT WakeContext,
__in ULONG TolerableDelay
);




Полное описание функции вы можете найти в MSDN. В рамках данной статьи нас интересуют только параметр TolerableDelay, который определяет максимальное допустимое отклюнение от заданного интервала.


Более подробно о таймерах в Windows можно прочитать в статье Timers, Timer Resolution, and Development of Efficient Code





Сделай это быстро





Еще один способ сделать программу более энерго-эффективной это научить ее делать нужные вещи быстро, на сколько это возможно. Добиться этого можно, например, оптимизировав код, путем использования SSE, AVX и других аппаратных возможностей платформы. В качестве примера хочу привести использование Quick Sync в Sandy Bridge для кодирования и декодирования видео. На сайте Tom's Hardware можно посмотреть результаты.


Допустим мы оптимизировали нашу программу, но насколько она теперь более энерго-эффективна, как это оценить? Очень просто - с помощью специальных программ и инструментов.





Инструменты для анализа энерго-эффективности





1. Intel Power Checker. Пожалуй самый простой и быстрый способ оценить энерго-эффективность своей программы.





Обзор и описание программы можно найти в блоге ISN


2. Intel Battery Life analyzer





Более сложный, но вместе с тем более информативный инструмент, служит для отслеживания различных активностей железа и софта, которые влияют на время работы от батареи.


3. Joulemeter от Microsoft





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



Где узнать больше


For more complete information about compiler optimizations, see our Optimization Notice.