Ниже изложены три основных принципа ОВС.
- Глобальный параллелизм. Одновременное выполнение последовательных задач на большом количестве простых компьютеров.
- Конструктивная однородность элементов и связей между ними. Однотипность компьютеров и соединение их в решётчатые структуры. Такой подход упрощает технологию производства и обеспечивает наращиваемость архитектуры.
- Переменная логическая структура. Логические связи между взаимодействующими компьютерами изменяются динамически, в соответствии с графом алгоритма [2].
Топология двухмерной решётки, лежащая в основе SEAforth-семейства, легко масштабируется: созданы мультикомпьютеры, имеющие 24, 40 и 144 узла на кристалле (см. рис. 1). S144 (переименованный в GA144) был воплощён в кремнии создателем SEAforth-архитектуры, Чарльзом Муром [11], когда последний, покинув IntellaSys, начал работу в собственной компании GreenArrays [12]. В дальнейшем, возможно, будет использоваться и топология тора, которая позволит сократить расстояние между наиболее отдалёнными узлами.
Рис. 1. Мультикомпьютеры S24, S40 и S144
Узлом SEAforth-решётки является 18-битный стековый компьютер C18 (см. рис. 2), c локальными ОЗУ (64 слова) и ПЗУ (64 слова) и низкоуровневым диалектом языка Форт [1] в качестве набора команд. Стеки данных (10 слов) и возвратов (9 слов) организованы, как кольцевые буферы.
Рис. 2. Компьютер C18
Очередное выполняемое узлом 18-битное слово представляет собой буфер до четырёх 5-битных инструкций. Выборка следующего слова начинается в тот момент, когда определяется, что остаток команд буфера инструкций не использует шину адреса. В пределах выполняемого слова возможен особый вид программного цикла (микроцикл), без обновления буфера инструкций.
Для взаимодействия с ближайшими соседями имеются порты. С точки зрения программиста это специальные адреса по которым узлы читают и записывают значения в одном или нескольких одновременно направлениях. Непосредственно на адрес такого порта можно передать управление. В этом режиме счётчик команд не увеличивается, а буфер инструкций заполняется словами от узла-соседа. Имеется также механизм неблокирующего опроса статуса портов, связанных с данным узлом.
Отдельный узел выполняет около 700 миллионов операций в секунду. Пиковое быстродействие мультикомпьютера S40 можно оценить в 28 миллиардов операций в секунду. Это ситуация, когда все узлы полностью загружены выполнением независимых задач. Количество потребляемой мультикомпьютером энергии непосредственно зависит от активности отдельных узлов.
Узлы на внешнем периметре SEAforth-решётки могут функционировать в режиме выделенных периферийных процессоров, благодаря чему отпадает необходимость в механизме обработки прерываний, а время отклика в задачах «реального времени» становится очень малым. Периферийные узлы подключаются к различным контактам и имеют специальные процедуры в ПЗУ для управления внешними интерфейсами. Предусмотрено использование внешних модулей памяти. Имеются узлы со встроенными АЦП и ЦАП.
Программы для SEAforth требуют ручного распределения по узлам решётки. Для программиста такого рода декомпозиция может ассоциироваться с понятиями сопрограммы, объекта или процесса. Возможен графический подход: указание расположения и связей для узлов, выбираемых из библиотеки типовых блоков. Многообещающим представляется сочетание интерпретатора скриптового языка, имеющего доступ к внешней памяти и реализованного на небольшом количестве узлов, с остальной частью решётки, функционирующей в SIMD-режиме.
В целом, радикальная архитектура SEAforth представляет собой вызов программисту, любящему изящные и неординарные решения.
Программа на VentureForth состоит из команд подключения библиотек, описаний макроузлов и отдельных узлов, команд вызова различных инструментов.
Ниже представлен пример «трубопровода» (см. рис. 3) на трёх узлах (1-2-3). Предполагается, что данные поступают с нулевого узла и принимаются без изменений на четвёртом. Отдельно определён макроузел pipe («труба»), далее его код размещён на соответствующих узлах решётки, с указанием конкретных входов и выходов.
Рис. 3. «Трубопровод»
\ определение макроузла macro: pipe, ( $IN $OUT) >np equ $OUT >np equ $IN \ параметры макроузла \ слово >np переводит номер узла в адрес соотв. порта : start here =p \ точка входа $IN # a! $OUT # b! \ инициализация регистров : forever @a !b forever -; \ цикл переброски данных macro; \ размещение на узлах решётки 01 {node 00 02 pipe, node} 02 {node 01 03 pipe, node} 03 {node 02 04 pipe, node}
Загрузочный поток содержит специальный заголовок, считываемый процедурой из ПЗУ, и выполняет следующие действия.
- На портах транзитных узлов располагаются «помпы»: микроциклы, «перекачивающие» информацию для последнего в пути загрузки узла.
- ОЗУ последнего узла заполняется соответствующим содержимым.
- На порту последнего узла выполняется код инициализации. В простейшем случае это «прыжок» на точку входа.
- Путь загрузки уменьшается на один элемент c конца. Пока путь не пуст, повторяются действия, начиная с п. 2.
Рис. 4. Порядок обхода всех узлов решётки для S40>33
Слово >stream ожидает на входе путь загрузки c общим количеством задействованных узлов и формирует в ответ требуемый поток, который возможно использовать далее для передачи на загрузочный узел через соответствующий внешний интерфейс.
Пример.
\ формирование загрузочного потока для узлов 33, 34 и 35 33 34 35 3 >streamНа практике удобно пользоваться универсальными потоками, такими, например, как s40>19, s40>32, s40>33 (см. рис. 4). В их именах отражён тип решётки (S40) и номер загрузочного узла (19, 32 или 33).
Явно указать код инициализации можно с помощью конструкции {run … run}. Если код инициализации не указан, загрузчик задействует вместо него «прыжок» на точку входа (here =p) данного узла.
Ниже показан пример уже знакомого читателю макроузла pipe, который в данном случае инициализирует регистры не в ОЗУ, а прямо на порту.
macro: pipe, ( $IN $OUT) >np =b >np =a \ запись параметров в переменные симулятора here =p : forever @a !b forever -; \ код инициализации {run a @ # a! \ инициализация регистров b @ # b! | forever -; \ переход на forever run} macro;
Имеет смысл использовать высокоуровневые программные конструкции в духе Форта, где это не противоречит требованиям по быстродействию.
Примером подобного подхода являются переменные, работа с которыми не затрагивает состояние регистров.
\ операции над переменной x : x ( - x) @p+ drop @p+ ; \ чтение : x! ( x) !p+ ; \ запись 0 , \ значение xСуществуют вариации на ту же тему: переменные, встраиваемые в код, переменные двойной длины и т.п.
Слова-объекты, подобные конструкции Форта CREATE … DOES> могут сделать программу более ясной и зачастую существенно экономят память. Объединение общего кода и различных наборов данных происходит в таких словах при помощи стека возвратов, значение с которого трактуется, как адрес начала данных. Также возможно использование регистра A и соответствующих команд автоинкремента, если все наборы данных расположены друг за другом (обычно начиная с нулевого адреса) и обрабатываются последовательно. Полезными примерами слов-объектов, использующих стек возвратов, являются poly и taps из библиотеки ПЗУ.
Для оптимизации небольших линейных участков кода я написал утилиту invent, которая относится к классу супероптимизаторов [7]. Она позволяет по заданному коду на Форте автоматически построить его аналог для C18, минимальный по размеру.
Организация мультикомпьютерных вычислений сводится к двум базовым подходам: конвейеризации и распараллеливанию [2]. Некоторые полезные алгоритмы в этой области можно почерпнуть в книге [4].
Конвейерная обработка цепью непосредственно связанных узлов встречается на SEAforth наиболее часто. Вычислительная нагрузка на ступени конвейера и фазы деятельности ступеней должны быть выравнены. Цепь узлов можно заставить работать параллельно, предварительно распространив нужные данные на узлы всех соседей. Слишком протяжённая цепь обработки вызывает накладные расходы на передачу сообщений наиболее отдалённым адресатам. Ситуацию можно улучшить, используя мультиконвейерную обработку: разбив данную цепь на несколько параллельно функционирующих коротких цепочек. Следует помнить, что передача сообщений занимает некоторое время даже при использовании выделенных узлов в качестве коммутационных элементов.
Благодаря возможности обмена программным кодом между узлами возникла событийно управляемая обработка. В её случае узлы, организующие некоторый вычислительный процесс, не содержат цикла взаимодействия по какому-либо протоколу. Единственное, что они делают, это «прыгают» на один из портов, ожидая прихода управляющей программы-события, которая вызовет ту или иную процедуру из памяти узла или изменит значение определённых ячеек ОЗУ, стеков или регистров.
Для переброски программы через заданное количество узлов удалённому адресату я придумал специальную процедуру. Она может действовать подобно загрузчику, генерируя код «помп» для транзитных узлов. В этом случае перемещается только сама программа, а все транзитные узлы заняты до тех пор, пока идёт передача.
В другом варианте код отправляющей процедуры располагается на каждом из транзитных узлов, а программа оформляется в виде пакета, в котором содержатся следующие сведения.
- Номер узла назначения.
- Размер программы.
- Слова программы, поступающие на порт узла назначения.
Благодаря событийно управляемой обработке возможна реконфигурация всей решётки или её части, то есть замена одной распределённой программы на другую. Обычно это делается с помощью дополнительных загрузочных потоков.
В ожидании на мультипорте появляется необходимость, если неизвестно, с какого направления придёт событие. Правильная работа загрузчика основывается на том факте, что изначально все узлы передают управление на мультипорты. В процессе работы загрузчика происходит «фокусировка»: управление переходит с мультипорта на конкретное направление. Мультипорты также используются для совмещения операций чтения и записи в одном адресе.
Ниже представлен вариант реализации макроузла pipe c помощью мультипорта.
macro: pipe, ( $IN $OUT) >np swap >np port+ =b \ вычисление адреса мультипорта here =p : forever @b !b forever -; {run b @ # b! | forever -; run} macro;С помощью неблокирующего опроса статуса чтения/записи портов (регистр iocs) возможно организовать буферизацию обмена между некоторыми узлами или как-то иначе «развязать» взаимодействующие узлы в плане очерёдности выполняемых операций.
Асинхронные точки останова создаются с помощью слова bp c именем заранее определённого слова на Форте, которое будет вызываться каждый раз, когда управление на данном узле перейдёт на адрес, где была объявлена точка останова. Слово-обработчик на Форте может, например, просматривать и изменять переменные состояния симулятора, читать и записывать данные в файлы. Наиболее часто этот механизм используется не для отладки, а при моделировании ввода-вывода и сбора разного рода статистики.
Графический профайлер вызывается с помощью слова heatmap («тепловая карта») с указанием необходимого для сбора статистики числа тактов симулятора. В качестве результата с помощью библиотеки SvgScript [18] создаётся графический файл в формате SVG, где изображена SEAforth-решётка, показаны актуальные связи между её элементами и цветом отражена степень вычислительной нагрузки отдельных узлов.
Имеется возможность отображения общей вычислительной загруженности решётки в процентах. Эта величина может использоваться при расчёте энергопотребления мультикомпьютером.
Примеры работы графического профайлера можно увидеть далее в статье.
- Создание прототипа на Форте. Для этих целей полезно иметь библиотеку поддержки SEAforth-арифметики с фиксированной запятой.
- Декомпозиция и планирование протоколов взаимодействия узлов.
- Создание программ для отдельных узлов, обособленное и совместное их тестирование на симуляторе. Создание макроузлов.
- Тестирование программного проекта. Сбор различной статистики по результатам моделирования на симуляторе.
- Сохранение проекта в одном из загрузочных форматов и тестирование на реальном мультикомпьютере.
Здесь, как и в других моих проектах, главный файл содержит только команды по размещению макроузлов на решётке мультикомпьютера. Описания же самих макроузлов находятся в отдельном файле.
С помощью инструмента heatmap построена «тепловая карта» проекта. Результат можно увидеть на рис. 5. Цвета в диапазоне от чёрного до красного отражают степень вычислительной нагрузки узлов.
Макроузел composer производит поток нот, которые поступают на router. Далее на шесть «струн» синтезатора (связка pluck и delay) приходят программные события: широковещательные сообщения сумматора и сообщения для индивидуальных голосов (доставляемые с помощью relay) об изменении параметров той или иной «струны».
Макроузел delay хранит 128 девятибитных значений на которых основана линия задержки дробной длины с интерполяцией. Чтение и запись элементов delay организованы макроузлом pluck в виде сопрограммы (команда ;:).
Остаётся добавить, что код проекта Musicbox входит в дистрибутив VentureForth в версиях для S24 и S40.Загрузка очередного пресета из флеш-памяти во время работы синтезатора (то есть реконфигурация некоторого множества узлов) возможна благодаря событийно управляемой обработке.
SEAtar состоит из «каркаса» и работающих под его управлением программ, составляющих пресеты и занимающих оставшуюся часть решётки мультикомпьютера (см. рис. 6). В «каркасе» имеются следующие макроузлы: MIDI-драйвер (midi-in и parser), ЦАП-драйвер (predac и dac18), таблицы нот и полифонии (voices), маршрутизатор сообщений (router), загрузчик пресетов (preset+).
В макроузле scripts хранятся специфичные для пресетов определения программных событий. Эти события в виде relay-пакетов отправляются на «голоса» синтезатора в ответ на приходящие MIDI-сообщения.
Имеется два типа генераторов формант (см. рис. 7): formant (FOF-синтез) и noise (фильтрованный шум). Данные для этих генераторов поступают из таблицы формант (formants) и формантного секвенсера (events и sequencer).
- ВЧ фильтрация микрофонных сигналов (hpmic), система управления направленностью с подавлением шума (fdmi, rdmi, dly, sub, avg).
- Банк из восьми БИХ-фильтров (sos, band1-band8) с асимметричной АЧХ.
- Многополосный компрессор на основе преобразования Гильберта (rh, re, ih, im, log2, exp2, div), сумматор (sigma).
Проект основывается на исходной Matlab-модели. Также использовалась реализация на языке Си для устройства-прототипа на TMS320C67x DSP фирмы Texas Instruments. В версии для S40 вычисления производятся с 36-битной фиксированной запятой. Для этого применяется режим «расширенной арифметики» с включённым переносом.
Реализация банка фильтров заслуживает отдельного упоминания. На каждую частотную полосу задействовано по два узла. Фильтры работают в параллельном режиме с предварительным распространением очередного звукового семпла по всем полосам. Макроузел sos используется для построения фильтров, имеющих до пяти секций второго порядка в первой прямой форме, удобной для вычислений с фиксированной запятой. Управление фильтром осуществляется с помощью интерфейсных слов, передающих коэффициенты вместе с указанием их типа. Полосы содержат до 16 коэффициентов на циклически прокручивающихся стеках. С помощью sos построена также ВЧ фильтрация микрофонных сигналов.
Данный проект разрабатывался географически распределёнными участниками. Крупные подсистемы оформлялись в виде библиотек макроузлов. Затем они тестировались на симуляторе обособленно и в различных сочетаниях друг с другом. В результате, на прототипах готового устройства система немедленно заработала в ожидаемом режиме.
[1] | Броуди, Л. Начальный курс программирования на языке ФОРТ. — Финансы и статистика, 1990. |
[2] | Воеводин В. В., Воеводин Вл. В.. Параллельные вычисления. — БХВ-Петербург, 2002. |
[3] | Евреинов Э. В. Однородные вычислительные системы, структуры и среды. — Радио и связь, 1981. |
[4] | Миллер Р., Боксер Л. Последовательные и параллельные алгоритмы: Общий подход. — БИНОМ. Лаборатория знаний, 2006. |
[5] | Хоар Ч. Взаимодействующие последовательные процессы. — Мир, 1989. |
[6] | Kindermann, Lars. MusiNum — The Music in the Numbers. http://reglos.de/musinum |
[7] | Massalin, Henry. Superoptimizer -- A Look at the Smallest Program. — Proc ACM ASPLOS'87, Sigplan Notices 22,10 (Oct 1987), 122-126. |
[8] | Montvelishsky, Michael. Hearing Aid with SEAforth. http://seaforth.googlegroups.com/web/Preso-HLS.pdf |
[9] | Веб-сайт компании IntellaSys. http://intellasys.net |
[10] | SEAforth® 40C18 Device Data Sheet. http://www.intellasys.net/templates/trial/content/S40C18_DataSheet.pdf |
[11] | Chuck Moore's colorForth, OKAD and S40 Forth Multicomputer chip. http://colorforth.com |
[12] | Green Arrays, Inc. http://greenarraychips.com |
[13] | VentureForth® S40C18. http://207.47.34.108/download/index.html |
[14] | DPANS94. http://www.taygeta.com/forth/dpans.html |
[15] | SwiftForth™ Overview. http://www.forth.com/swiftforth/index.html |
[16] | Gforth. http://www.jwdt.com/~paysan/gforth.html |
[17] | VentureForth® Programmers Guide. http://www.intellasys.net/templates/trial/content/VF_ProgrammersGuide.pdf |
[18] | PostScript-подобный язык с выводом в формате SVG. Исходный текст на ANS Forth и некоторые примеры использования. http://peter.sovietov.com/app/svgscript.zip |
[19] | The Karplus-Strong Algorithm. https://ccrma.stanford.edu/~jos/pasp/Karplus_Strong_Algorithm.html |
[20] | FOF synthesis. https://ccrma.stanford.edu/~serafin/320/lab3/FOF_synthesis.html |