Пыль

7 февраль, 2007 - 17:44Андрей Зубинский

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

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

Но что произойдет, если попытаться разумно объединить слабые вычислители? "Слабые" - это даже мягко сказано, речь идет не о стареньких CPU "настольного класса" с тактовыми частотами порядка нескольких сотен мегагерц. Мы говорим о невероятно живучих 8-битовых микропроцессорах и контроллерах, о крохотных объемах памяти, и главное - об энергопотреблении, совершенно незначительном по меркам мира "настольных" вычислений. Естественно, прежде чем мы попытаемся ответить на поставленный вопрос, традиционно попробуем разобраться с главным - зачем и кому затрачивать усилия на разумное объединение совершенно ничтожных "вычислительных пылинок" (это, к слову, не красивый эпитет, а термин - слабые локальные вычислительные узлы принято называть motes, или пылинки)?

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

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

Можно считать, что в первой части этой статьи наступил момент истины - даже полученное (пусть и "на пальцах") обоснование какого-то проектного решения вовсе не дает ответа на вопрос о принципиальной необходимости созданных на основе этого проекта устройств. И правда, а зачем и кому могут быть нужны беспроводные сети, объединяющие "вычислительные пылинки"? Конечно, можно привести пару примеров использования подобных сетей и счесть ответ найденным. Но мы поступим иначе. Итак, мы уже располагаем совершенно доступными сверхвычислителями. Да-да, та производительность, которая в 1988 г. давала основание приписывать к слову "компьютер" гордую приставку "супер", - те самые 2 GFLOPS - уже в 2002 г. стала почти обыденной, "настольной". Быстрые, дешевые и "умные" последовательные интерфейсы, позволяющие в каком-то смысле использовать эту производительность в "интересах" сторонних устройств, превратились в обязательный атрибут любой копеечной конструкции невычислительного характера (проигрыватель, фотоаппарат). Разработки, еще недавно бывшие сугубо специализированными, также стали активно проникать на массовые рынки, например изначально создаваемая для автомобильных применений сеть CAN заинтересовала разработчиков smart homes ("интеллектуальных жилищ"), системы сверхширокополосной связи получили однокристальное овеществление и в маломощных вариантах обещают в ближайшее время стать беспроводными аналогами массового USB. То есть сегодня уже имеются и доступные достаточные для решения сложнейших задач вычислительные мощности, и средства "загрузки" этих мощностей информацией, поступающей от сторонних устройств. Иными словами, созданы все предпосылки для очередного события, соответствующего предсказаниям на основе закона Белла. Это эмпирическое правило, аналогичное закону Мура, утверждает, что примерно каждые десять лет появляется новый класс вычислительных систем. И сейчас мы можем говорить о зарождающемся классе систем потоковой обработки информации, получаемой наблюдениями за реальным миром в реальном времени. Несмотря на то что определение явно нуждается в дополнительных пояснениях, сразу приведем примеры уже существующих систем этого нового класса. Наиболее яркий "первенец" в новом классе - созданная исследователями Университета Беркли система мониторинга погодных условий и состояния почвы. 150 автономных "пылинок", объединенных радиосетью, успешно отработав четыре месяца, создали поток информации из 650 тысяч замеров. И хотя объектом исследования являлась сама по себе система, полученный информационный массив был не "учебным", а крайне необходимым для специалистов, занимающихся изучением миграций морских птиц и выбора ими мест гнездования. Даже этот пример позволяет без усилий определить одну крайне перспективную неисследовательскую область применения сетей из "пылинок" - сельское хозяйство. Здесь эффективный и дешевый мониторинг крупных площадей - задача, еще ожидающая своего красивого решения. И, безусловно, - нужная. Подобных перспективных применений "пыли" можно найти множество - от сугубо мирных до военных.

Новый класс вычислительных систем будет образовываться объединением мощной и доступной централизованной обработки информации с беспроводной сетью ее сбора, состоящей из "пылинок". И настоящей новизны в такой системе немало - начиная от алгоритмов синхронизации в радиосетях и автоматического их конфигурирования до построения полузаказных "пылинок" по технологии SOC (система на чипе), допускающих быструю "настройку" на потребности заказчика.

Несмотря на пока экспериментальный характер, аппаратно-программные средства "пылинок" уже прошли несколько технологических этапов. К слову, эта недолговременная эволюция привела к весьма интересным открытиям. Так, разработчики "пылинок" уже получили оценки энергетических затрат различных процессов, которые многим могут показаться весьма необычными. Передача одного байта по маломощному радиоканалу ZigBee, оказывается, ощутимо... дешевле (в смысле потребляемой энергии) и быстрее, чем сохранение этого байта в энергонезависимой флэш-памяти: радиопередача "оплачивается" полутора микроджоулями, запись - тремя микроджоулями энергии источника питания; передача байта по радиоканалу ZigBee со скоростью 250 Kbps длится 32 мс, запись во флэш-память - 78 мс. Эти цифры означают, что в определенных случаях действительно выгоднее не хранить данные в "пылинке", а "выбрасывать" их в радиосеть - это более чем в два раза увеличит продолжительность срока автономной работы "пылинок". Такой результат в самом деле интересен и неочевиден, особенно с учетом того, что сравниваемые технологии относятся фактически к одному поколению.

Маленькое - не значит игрушечное

Программное обеспечение "пылинок" - пожалуй, самая интересная составляющая нового класса вычислительных систем. Казалось бы, что можно ожидать от ОС, ядру которой требуется всего 400 байт памяти программ и данных? Оказывается, немало: трехуровневой компонентной архитектуры, параллелизма на уровне задач и событий, мощной поддержки развитыми кросс-средствами, включающими даже трансляторы с надмножества языка C, ориентированного на решение специфических для "реактивных" приложений задач. Но начнем по порядку.

Операционная система TinyOS на сегодняшний день является хорошо отработанным продуктом, прошедшим довольно длительный период эволюции. Текущую стабильную ее версию (2.0 или T2) можно считать образчиком "малых ОС", идеально пригодным для изучения и повторного использования в собственных разработках - ведь система распространяется на основе крайне либеральной, схожей с BSD, лицензии. Кроме того, за продолжительное время развития TinyOS "обросла" массой мощных средств кросс-разработки (таких как, например, Viptos). Аппаратные средства, требуемые для использования этой системы, достаточно скромны и доступны всем желающим (по крайней мере, в крупных промышленных городах Украины) - микроконтроллеры семейства AVR производства Atmel и MSP430 - Texas Instruments, и чипы, реализующие приемопередатчик ZigBee (например, CC2420).

TinyOS привлекательна в первую очередь трехуровневой архитектурой абстрагирования аппаратных средств, позволяющей сравнительно легко портировать данную систему: это немаловажное достоинство - написание мобильных программ даже в POSIX-стандартном мире - совсем не простое занятие, а уж решение задачи создания высокомобильного ПО для сверхмалых вычислителей тем более далеко от тривиальности. HAA (Hardware Abstraction Architecture) - архитектура абстрагирования аппаратных средств TinyOS включает уровень их представления (HPL, Hardware Presentation Layer), абстракции (со знакомой "настольной" аббревиатурой HAL), и наконец, аппаратно-независимый уровень, HIL (Hardware Independent Layer). Назначения их вполне традиционны - на уровне HAA формируются обобщенные представления аппаратных ресурсов вычислителя (регистров, портов ввода-вывода и т. д.) в виде интерфейсов языка программирования. Крайне ограниченные ресурсы "пылинок" требуют минимальной затратности от каждой подсистемы TinyOS, и в этом смысле реализацию HAA можно считать идеальной, так как она не содержит никакой информации о состояниях абстрагируемого "железа". Иными словами, она беззатратна: HAA не требуется ни одного бита памяти, ни одного такта времени исполнения. На уровне HAL абстракции HAA обобщаются до уровня класса однотипных аппаратных средств, а соответствующие интерфейсы HAL имеют имена, отражающие этот класс (например, начинающиеся с префикса "класс_").

Еще одно достоинство TinyOS - компонентность. По сути, вся эта система является набором повторно используемых системных компонентов - равноправных с точки зрения программиста программных модулей и "облаток" из HAA и HAL. Компоненты TinyOS аналогичны объектам (в том смысле, что они инкапсулируют состояния с функциональностью). Но, в отличие от распространенных объектных систем С++ и Java, компонентная система TinyOS требует от программиста при описании компонента-объекта не только указания перечня функций, реализуемых этим объектом, но и явного указания используемых им функций, реализуемых сторонними объектами. Кроме того, в TinyOS компонент A может "добраться" до инкапсулированных другим компонентом B данных только с помощью механизмов доступа, предусмотренных разработчиком компонента B.

Подмножество функций, реализуемых объектом и относящихся к одному из аспектов описываемого им функционирования, в терминах TinyOS называется интерфейсом. На языке высокого уровня nesC, кросс-компилятором которого сопровождается поставка TinyOS, описание (точнее, спецификация) компонента выглядит в общем виде так:

module имя_компонента
provides interface имя_интерфейса ; /
uses interface имя_интерфейса ;
 
interface имя_интерфейса
command имя_функции_1() ;
...
command имя_функции_N() ;
 

Более того, nesC позволяет описывать и параметризованные интерфейсы, и общие (generic) компоненты. Это означает: если обычный компонент TinyOS в терминах объектного программирования фактически является синглетоном, то обобщенный компонент такого ограничения лишен.

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

Теперь о компонентах TinyOS известно почти достаточно для того, чтобы вкратце ознакомиться с механизмом "монтажа" приложения из них (в отличие от традиционной процедуры "сборки" (linking), здесь используется даже другой термин - wiring, монтаж). Упомянутое "почти достаточно" требует еще одного пояснения (хоть оно и по некоторому рассуждению очевидно). Компоненты TinyOS - это всего лишь поименованные функции и переменные, "упрятанные" в свои собственные локальные пространства имен. Для того чтобы компонент A смог воспользоваться ресурсами компонента B, необходимо "отобразить" потребности компонента A с возможностями компонента B. Эта процедура "отображения" описанных ключевыми словами provides и uses интерфейсов и называется монтажом. А для задания ее поведения в явном виде программистом в языке nesC существует специальный класс компонентов - конфигурации.

Еще один аспект понятия "компонент" в TinyOS - описание механизма трансформации его (компонента) статической сущности в исполняемую сущность. Компонент не может непосредственно активировать какую-либо из инкапсулированных в нем функциональностей (иными словами, вызвать одну из его функций). Вместо этого он запрашивает у ОС право на запуск задачи. Этот механизм запроса (post - в терминах TinyOS) превращает задачу (task) в вычисления, отложенные до разрешения ядром ОС. Иначе говоря, в TinyOS компонент, затребовавший выполнения какой-либо функциональности, получает ответ от ядра ОС о приеме запроса немедленно, но выполнение запрошенного наступит только тогда, когда до него дойдет очередь, поддерживаемая планировщиком ОС. Кстати, если вам не нравится такая политика TinyOS, вы можете просто заменить ее компонент "планировщик" на свой собственный.

В общем, ОС, для выполнения ядра которой требуется менее 400 байт памяти программ и данных, может оказаться на удивление непростой. То же можно сказать и о языке nesC, благодаря которому и создана TinyOS. Хотя, если вы знаете C или любой C-подобный язык, изучение nesC не покажется вам трудным. Надо только учесть важнейшие особенности этого языка, делающего его великолепным инструментом разработки встраиваемых приложений. Во-первых, в nesC вообще нет механизмов динамического выделения памяти (как быть без них - вопрос, безусловно, хороший, но параметризованные интерфейсы и обобщенные компоненты во многих случаях позволяют им вообще не задаваться). Во-вторых, в nesC не предусмотрен механизм раздельной компиляции. Вместе эти свойства означают, что программа на nesC может быть объектом так называемой "полной оптимизации", т. е. компилятор при выполнении процедуры оптимизации кода может использовать информацию сразу о программе в целом, что исключительно важно с точки зрения построения эффективных программ. Но это далеко не все - благодаря этим особенностям можно легко проверять и даже верифицировать программы на nesC.

Внимательный читатель уже должен был заметить, что описания TinyOS и nesC в этой статье образовали как бы "мешанину". И действительно, в программном обеспечении "пылинок" крайне трудно отделить язык реализации от ОС. Дело в том, что TinyOS, по сути, является неявным представителем небольшого класса гибридов "ОС-язык". При этом взаимозависимость здесь намного выше, чем, например, в знаменитой комбинации "ОС-язык" Forth, и TinyOS готовит еще один сюрприз - несмотря на большее единение ОС и языка, система обладает великолепными показателями производительности и компактности реализации. Так, если Forth предусматривает формирование пусть минимальной, но все же виртуальной машины (что неизбежно означает какие-нибудь, да потери), TinyOS и nesC позволяют использовать все возможности вычислителя - до последнего бита и каждого такта.

В принципе, для первого знакомства сведений о TinyOS достаточно. Остается лишь упомянуть о том, что она создана в соответствии с лучшими традициями классического академического проекта, отлично документирована (при составлении документации используются даже развитые графические пакеты с открытыми исходными текстами) и очень интересно реализована. Единственное маленькое "но" - TinyOS разрабатывалась и продолжает совершенствоваться в UNIX-подобных системах, и для ее кросс-средств ОС Windows - далеко не лучшая среда (хоть подобная комбинация и предусмотрена). Впрочем, это еще один повод оценить по достоинству возможности современных дистрибутивов Linux - операционной системы, приобретающей все большую популярность среди разработчиков встраиваемого ПО.