Опыт автоматизации управления FPGA-стендами для распределенной команды
В software-разработке с автоматизацией обычно все неплохо: более-менее понятно, как настроить CI и автоматизировать отдельные этапы CI-конвейера. Есть множество готовых решений и практик. Но, когда речь заходит об автоматизации тестирования на «железе», появляется множество нюансов. Например, не всегда понятно, как автоматизировать процессы, которые обычно делают люди, — банальную перезагрузку устройства в другом городе. Или другая особенность — целевые аппаратные ресурсы масштабируются не так хорошо, как софт, поэтому приходится придумывать свои подходы к распределению времени доступа к стенду для СI-конвейеров и инженеров.
Опытом автоматизации процессов, связанных с разработкой на FPGA-стендах, делится Игорь Большевиков, инженер по системному программированию систем на кристалле в YADRO. В статье он расскажет о решениях для удаленной загрузки плат, бронирования аппаратных ресурсов и технической поддержки пользователей из распределенной команды.
- какие устройства входят в состав тестовых стендов YADRO
- что и как можно автоматизировать в процессе работы со стендами
- почему команде не подошло готовое решение
FPGA-стенды и их пользователи
Для введения в контекст задач, которые мы автоматизировали, расскажу, что у нас за стенды и кто с ними работает.
В нашем департаменте по большей части работают с вычислительными системами. В состав наших стендов входят:
- Модуль управление питанием — PDU.
- Сервер — виртуальная машина или железный сервер с набором программного обеспечения. На нем стоят HW server (Vivado), который позволяет управлять FPGA-платой, OpenOCD для начального управления встраиваемым CPU, терминал ввода-вывода. Здесь же живут скрипты, используемые для автоматизации, в тот числе скрипты, взаимодействующие через CLI с Vivado, скрипты, используемые для взаимодействия с OpenOCD, скрипты взаимодействия с системой бронирования, управления питанием портов USB-хабов и PDU.
- USB-хаб с поддержкой PPPS, порты которого можно включать и выключать программно. Это позволяет не звать коллегу в лабораторию, когда у вас «отвалился» программатор или другое USB-устройство и нужно его перезагрузить.
- Программаторы для FPGA-платы, CPU, USB-UART, USB-I2C устройства и прочая периферия.
- Сама плата с FPGA или несколько плат, соединенных в один кластер.
Стенды находятся в нескольких лабораториях в разных городах. В каждой лаборатории есть дежурный — человек, который помогает решать проблемы с «железом» на месте. Большинство пользователей же работают со стендами удаленно — из дома или офисов компании.
Если говорить о том, кто работает со стендами, то в нашем процессе команды RTL-разработки создают описание проектируемых устройств, после чего оно попадает к команде прототипирования на FPGA. Именно с этого момента активно используются стенды. К работе над устройствами подключается множество команд из различных подразделений, и всем необходимо предоставить доступ к оборудованию, которого значительно меньше, чем желающих с ним поработать.
Сложности с прототипированием на стендах
В нашем случае, когда пользователей и сценариев работы со стендами много, возникает ряд типовых сложностей.
Первая — это множество вариантов загрузки. У каждой команды может быть свой сценарий работы со стендом: используются разные прошивки с разным функционалом, для каждого варианта может быть свой софт, запускаемый на данной прошивке, разная периферия. И это приходится учитывать при автоматизации, чтобы удовлетворить все возникающие потребности большого количества команд.
Когда у вас много инженеров, вариативность «поднятия» стенда порождает сложность с документацией. Нередко команды используют сценарии работ со стендом других команд. И они не всегда хорошо описаны: зачастую даже не ясно, к кому обращаться за помощью при использовании конкретного варианта.
Загрузка — это еще и множество ручных манипуляций. Для того, чтобы запустить прототип на FPGA и операционную систему на нем, нужно потратить много времени. Типовой ручной процесс загрузки ОС на прототипе включает в себя массу мелких шагов, которые пользователю нужно выполнять последовательно, непрерывно следя за процессом. Поскольку иногда инженеру нужно совершать такие манипуляции несколько десятков раз за день, это становится проблемой. Гораздо удобнее иметь кнопку «сделать все хорошо», чтобы пользователь мог нажать на нее и заниматься своими делами, пока прототип загружается.
Отдельная сложность — в том, что людей гораздо больше, чем стендов. Невозможно поставить каждому инженеру на стол личный прототип из-за высокой стоимости оборудования. В результате на стенд может приходиться до 10 человек, и нужно каким-то образом упорядочивать доступ к нему.
Все это значительно замедляет работу команд. Поэтому мы решили, что нужно автоматизировать процессы работы с FPGA-стендами. Главные требования к системе были лаконичными:
- упростить «поднятие» стенда,
- решить вопрос множественного доступа так, чтобы разным людям было удобно пользоваться одним и тем же стендом.
Что автоматизируем
Можно выделить типовой набор шагов, которые необходимо выполнять каждый раз при работе со стендом:
- Включить/пересбросить питание стенда.
- Пересбросить питание USB-портов, тем самым перезагрузив периферийные устройства на шине USB, подключенные к стенду.
- Прошить clock-генератор, потому что наши стендовые платы требуют управления тактовым генератором перед началом прошивки FPGA.
- Прошить FPGA.
- Управление VIO.
- Загрузка программного обеспечения в CPU.
- Управление VIO.
- Загрузка программного обеспечения в CPU.
Список специфичен для наших сценариев работ, но, в целом, действия можно заменить на манипуляцию с любой другой периферией без потери смысла. Мы хотели по максимуму автоматизировать эти рутинные процессы запуска. Давайте коротко посмотрим, что за ними скрывается.
Есть FPGA-плата, и в нее нужно как-то залить прошивку, желательно удаленно. У Xilinx есть отдельный HW server — агент, который можно поставить на стендовый сервер, подключенный к FPGA. Это значит, что в теории стенд можно прошивать удаленно через Vivado и TCL-скрипт. Скрипт можно обернуть в Python, что дает предпосылки для автоматизации процесса.
Дальше нужно залить софт в прототипируемый процессор. Мы используем дебаггер OpenOCD с открытым исходным кодом. Он имеет клиент-серверную модель: мы разворачиваем сервер на стендовый компьютер, удаленно дергаем команды и грузим программное обеспечение.
Сам по себе запущенный прототип процессора, который не общающийся с внешнем миром, не особо интересен. Инженеру нужно общаться с прототипом через терминал. Если есть сеть, то поднимаем SSH, и все в порядке. Но она доступна далеко не на всех прототипах. В этом случае придется по старинке использовать UART. С самим по себе UART удаленно поработать не выйдет, но всегда можно подключиться через SSH к стендовому серверу, а с него — к терминалу по UART. С другой стороны, можно использовать один из open source-фреймворков, которые позволяют пробросить USB-трафик (в том числе от usb2uart-устройства) через TCP-стек и подключиться к тестовому FPGA-стенду удаленно. Так что данная задача тоже неплохо автоматизируется.
И наконец, нужно управлять периферийным оборудованием на стенде. На всех наших отладочных платах стоит как минимум clock-генератор, который нужно сконфигурировать перед началом работы. Тут все зависит от конкретного периферийного оборудования, но в нашем случае это довольно просто автоматизируется.
Первый подход: Labgrid
Итак, у нас есть понимание, что хотелось бы автоматизировать. Дальше нужна система, которая позволит это сделать и которой будет удобно управлять. Первое, на что мы обратили внимание, это Labgrid.
Labgrid — это библиотека Python с открытым исходным кодом для удаленного управления различными embedded-платформами, в том числе FPGA. Поскольку она ориентирована на автоматизацию тестирования встраиваемых платформ, предполагается работа в связке с Pytest. На базе библиотеки «из коробки» доступны CLI-инструменты, позволяющие управлять распределенной системой стендов.
Labgrid состоит из трех основных компонентов:
- Координатор (coordinator)
Это брокер сообщений, который хранит список всех ресурсов для клиентов и уведомляет их об изменениях. Пользователю, как правило, ничего не нужно знать о координаторе. - Экспортер (exporter)
Это программный пакет, который ставится на стендовый компьютер. Это может быть виртуальная машина, голый сервер либо контейнер. Экспортеру передается описание того «железа», с которым он будет работать, например, серийные номера программаторов, знание, что к каким USB-портам подключено, сетевой IP целевой платы. Экспортер регистрирует все сконфигурированные ресурсы при подключении к маршрутизатору и обновляет их параметры при необходимости. Также он может перенаправлять потоки ввода-вывода (например, UART) от клиента к «железке», от «железки» к клиенту. - Клиент (client)
Наиболее сложная часть Labgrid, сущность, которая содержит все алгоритмы управления «железом». Здесь живут драйверы, ваши собственные скрипты и бинарные артефакты. Именно клиент управляет всем процессом.
Мы попробовали прикрутить Labgrid к нашим стендам и выделили следующие плюсы и минусы:
Labgrid предоставляет довольно много полезных фич, главная из них — это поддержка большого количества драйверов устройств. В терминологии библиотеки это модули, которые управляют аппаратной или программной сущностью.
Драйверы позволяют управлять OpenOCD, QEMU и Docker через более-менее похожие API. Также можно управлять (наподобие expect) терминалами U-boot, barebox, Linux, различными USB-устройствами, PDU. Среди прочего, в Labgrid есть драйвер sigrok, который позволяет удаленно подключаться к довольно большому числу разных логических анализаторов и опрашивать устройства в CI. Вы можете автоматизировано манипулировать стендом, получить результат, оценить, правильно или неправильно прошел тест, и принять дальнейшее решение.
Если готового драйвера не нашлось, Labgrid можно кастомизировать. При желании можно писать свои драйверы на базе уже существующих классов устройств или создавать новые.
Также Labgrig умеет бронировать ресурсы. Например, у вас есть одна плата и два человека, которые хотят на ней поработать. Если они начнут делать это одновременно, получится коллизия: один прошивает плату, а другой в середине процесса ее перезагружает. Бронирование ресурсов в Labgrid имеет внутри что-то вроде mutex. Вы пришли на стенд, защелкнули mutex, и после этого другие инженеры не смогут воспользоваться платой — клиентское приложение не даст отправить команды удаленному устройству.
Еще один плюс библиотеки — интеграция с фреймворком Pytest. Это может быть удобно, поскольку у фреймворка есть интеграция с различными внешними инструментами.
Если говорить о минусах, то самыми критичными для нас были следующие:
- Хоть «из коробки» и доступно большое количество драйверов и они кастомизируемы, рано или поздно придется добавлять свои. И вот тут нас ждал неприятный сюрприз: сам драйвер может быть скриптом на Python в 5−10 строчек, но, чтобы понять от каких классов сделать наследование и как передать нужные параметры между компонентами системы, нужно перерыть кучу кода, местами не самого лучшего. Хотя документация довольно подробна, при добавлении или кастомизации драйверов, хоть немного отличающихся от приведенных примеров, приходится перелопачивать половину кода Labgrid. В итоге общий процесс добавления или изменения даже небольшой функциональности превращается в приключение на пару недель.
- Бронирование, о котором я говорил выше, есть, но довольно примитивное. Бронирование в клиенте лишь разрешает или запрещает исполнение удаленной команды, но не имеет средств для планирования работ: не умеет ставить пользователей в очередь и не регламентирует время, на которое пользователь может взять стенд. Если со стендом работает больше двух человек, это уже может быть не совсем удобно. Кроме того, Labgrid различает пользователей клиента по именам Unix-пользователей. Если вы и ваш коллега запускаете Labgrid из одного и того же образа контейнера, то библиотека посчитает, что вы один и тот же пользователь.
И наконец, разным командам нужно взаимодействовать со стендом, но не все инженеры из них знакомы с Python. А для написания сценариев управления «железом» Labgrid требует знания некоторых не самых базовых понятий языка.
В целом, Labgrid неплох, и его вполне можно использовать, но для нас минусы инструмента перевесили плюсы. Кроме того, у соседней команды в департаменте уже были наработки собственной системы автоматизации управления стендами. Мы решили объединить усилия и сделать систему под свои потребности.
Второй подход: своя система автоматизации
Как говорилось в начале статьи, «поднятие» прототипа на FPGA-стенде — процесс, допускающий много вариаций. И если наша команда будет продумывать все возможные сценарии, то мы только этим и будем заниматься. Поэтому мы решили дать пользователям понятный интерфейс взаимодействия со стендами, чтобы они могли сами создавать сценарии, но понятным для них способом. Вкратце расскажу, какие варианты мы перебрали и к чему пришли.
Одной из концепций, которую мы прорабатывали, был декларативный интерфейс:
Если вы работали с плейбуками Ansible или CI в GitLab, то наверняка знакомы с подобным стилем описания. Декларативный стиль подразумевает, что системе даются инструкции, что делать, но не как ей это делать. Все детали скрыты от пользователя, и ему больше не нужно думать, что происходит «под капотом». Достаточно попросить систему взять конкретные файлы и выполнить необходимые действия.
Вариант вполне рабочий, можно либо написать собственный парсер для листинга такого формата, либо создать свой модуль для Ansible. Но в конечном счете мы решили упростить концепцию и не делать свой FPGA Ansible, а воспользоваться Python в урезанном варианте. Мы не просим пользователей знать язык и писать свои скрипты, а даем документацию с примерами и готовый список команд, который достаточно выстроить в необходимом порядке:
Такой подход всех устроил, поэтому мы остановились на этом варианте.
На данном этапе мы сделали вывод, что существующие системы могут быть удобны на старте, но по мере кастомизации под себя становится проще написать свой инструмент. Он будет менее универсальным, зато покроет именно ваши потребности, его будет проще поддерживать, и он будет понятным для ваших пользователей. В итоге для закрытия наших потребностей понадобилось написать лишь обертку для CLI Vivado, клиента для OpenOCD, скрипты, управляющие PDU, PPPS USB, скрипты для нашей периферии и прикрутить над этим всем удобный интерфейс.
Мы получили результат, который может ускорить работу наших команд, но вопрос о бронировании стендов оставался открытым.
Бронирование стендов
Итак, у нас много пользователей-инженеров и не так много плат. Было важно создать систему, которая в любой момент ответит на вопрос «Когда можно поработать на стенде?».
Время для работы на стендах нужно инженерам и CI-конвейерам. Задача — сделать так, чтобы разные пользователи не мешали друг другу. Изначально мы использовали общие чаты в мессенджере: каждый отписывался, что занял плату и освободил ее. Какое-то время это работало, но с ростом парка стендов этот процесс превратился в хаос.
Мы заменили чаты на единый для всех сайт-календарь. Пользователи получили возможность зайти на сайт, залогиниться, выбрать нужную отладочную плату и увидеть, когда она будет свободна. Там же они могут забронировать время работы со стендом на будущее. По смыслу похоже на любое приложение-календарь: решение простое и позволяет пользователям не ждать своей очереди, а планировать загрузку и необходимые работы.
Со временем сайт-календарь начал обрастать дополнительными возможностями и походить на аналог Jenkins. В нем появился test runner, который может планировать тесты, делать ночные прогоны и так далее. Время для работы CI бронируется в календаре автоматически. В зависимости от времени суток и ряда других параметров приоритет на конкретное время будет у автотестов или у людей. Главное — теперь все инженеры могут спокойно планировать свои работы, а не мониторить чаты на предмет свободного стенда.
Одним из недостатков системы бронирования ресурсов в Labgrid мы отметили слабую модель различения пользователей. Чтобы решить эту проблему, в своей системе мы разработали агент, который ставится на лабораторный компьютер и управляет доступом по SSH. Пользователь заходит в систему бронирования и в запланированное время — на стенд. Как только отведенное время работы заканчивается, агент «выкидывает» пользователя из системы и не дает в нее вернуться. Если настолько жесткие рамки не нужны, можно динамически управлять Unix-группами: пользователи всегда могут зайти на сервер, подключиться по SSH и что-то поделать. Но если время не забронировано в планировщике, то доступа к «железу» все равно не будет.
Агент, который управляет доступом пользователей в систему, также следит за оборудованием. У него есть лист конфигурации с описанием оборудования, что может быть удобно при запуске автоматизированных тестов. Если тот или иной стенд сейчас на обслуживании, то мы просто выключаем сервис агента и конкретный стенд пропадает из системы бронирования.
Виртуализация ресурсов
Как гласит закон Мерфи, если есть вероятность, что какая-нибудь неприятность может случиться, то она обязательно произойдет. После того как мы автоматизировали «поднятие» стендов и настроили процесс управления их бронированием, то начали надеяться, что проблема решена. Однако к нам стали периодически приходить пользователи с вопросом: «Кто сломал мой прототип?».
Мы отправились искать причину. Она оказалась в том, что у нас остался подход к управлению доступом к «железу» еще с того момента, когда были всего пара стендов и небольшая группа пользователей.
Изначально мы использовали простую схему: один выделенный под стенды сервер, и в него через USB-хабы подключены программаторы и прочая периферия от нескольких стендов. Пока стендов мало, все хорошо, но когда к одному стенду подключено 15 JTAG-программаторов для FPGA и 15 программаторов для прототипа, то можно легко запутаться и взять для работы программатор от чужого стенда. В итоге можно было случайно начать прошивать FPGA с соседнего стенда, на котором прошла уже половина двухнедельного теста на стабильность. В итоге тест потерян, и нужно начинать все с начала.
Очевидно, что нужно изолировать стенды друг от друга. В качестве решения мы пришли к довольно простой модели и сделали виртуализацию ресурсов. Теперь у каждого стенда своя виртуальная машина, в которую проброшены порты только одного стенда. Благодаря этому невозможно случайно сломать чей-то процесс отладки. Дополнительный бонус — более строгая изоляция программных ресурсов. Если вдруг пользователь каким-то образом сломает ОС на виртуальной машине, мы не потеряем все стенды, проблема коснется только одного.
Техподдержка пользователей
Последняя проблема, которая сохранялась на всех этапах, — это сложность координации и поддержки пользователей. Процесс запуска стендов менялся, менялась система бронирования, но документация не всегда успевала за изменениями. К тому же не всегда было понятно, где именно искать ответы на интересующий вопрос, у кого узнать подробности, кто сегодня дежурный и кому именно обращаться с вопросом по «железу».
Мы пришли к идее, которая хорошо известна в software-разработке и помогает в решении проблем внутренних пользователей компаний, — service desk. Сейчас сайт в разработке, есть только прототип, но я опишу задумку.
Пользователь заходит на сайт и выбирает нужную категорию. Например, «хочу установить ПО на стенд», «хочу поменять что-то в составе стенда». Бэкенд превращает запрос в тикет, который автоматически назначается на нужного исполнителя в системе управления задачами. И сразу правильный человек решает задачу: пользователю не нужно самостоятельно искать ответственного за какой-либо компонент системы.
Кстати, service desk решает еще одну смежную проблему. Дежурные по лаборатории с «железом» — разные в разные дни. Иногда случается так, что они вносят в систему взаимоисключающие требования пользователей. Мы верим, что единая точка входа и открытость окружающих задач поможет дополнительно валидировать запросы и предотвратить ситуацию, когда необходимые пользователям изменения противоречат друг другу.
Выводы
В процессе работы над автоматизацией управления FPGA-стендами мы сделали несколько выводов:
- Автоматизация должна быть «дешевой» как со стороны пользователя, так и со стороны разработчика. Сложной системой никто не пользуется, предпочитая старые «ручные» варианты. В идеале система должна быть гибкой, но простой в использовании и обслуживании. Хорошо помогает декларативный синтаксис.
- Общая система бронирования — это удобно. Возможно, в ней нет потребности, если у компании небольшой штат, инженеры сидят в одном кабинете и могут договориться, кто и когда займет стенд. В случае распределенной по городам большой команды нужен какой-то инструмент планирования времени работ.
- Ресурсы нужно изолировать. Причем не только программные, но и аппаратные. Кажется, это очевидно, но мы не сразу пришли к этой идее.
- Поддержка должна быть консолидированной. Важно, чтобы у пользователей была единая точка входа, а решения по поступающим запросам принимались централизованно.