Введение

MAJC (Microprocessor Architecture for Java Computing) - это многоядерный, многопоточный, очень длинный инструкционный словарь (VLIW) микропроцессора Sun Microsystems, разработанный в середине-конце 1990-х годов. Первоначально названный процессором UltraJava, процессор MAJC был нацелен на запуск программ Java, чье "позднее компиляция" позволила Sun принять несколько благоприятных дизайнерских решений. Процессор был выпущен на двух коммерческих графических картах от Sun. Уроки, извлеченные в отношении многопотоков на многоядерном процессоре, послужили основой для более поздних реализаций OpenSPARC, таких как UltraSPARC T1.

Переместить планирование инструкций в компилятор

Как и другие проекты VLIW, в частности Intel IA 64 (Itanium), MAJC пытался улучшить производительность, перенеся несколько дорогостоящих операций из процессора в соответствующие компиляторы. В общем, конструкции VLIW пытаются устранить планировщик инструкций, который часто представляет собой относительно большую часть общего транзисторного бюджета процессора. С этой частью процессора, удаленного из программного обеспечения, эти транзисторы могут использоваться для других целей, часто для добавления дополнительных функциональных единиц для обработки большего количества инструкций одновременно или для увеличения количества кэша памяти для сокращения времени, затрачиваемого на ожидание данных из гораздо более медленной основной памяти. Хотя MAJC разделял эти общие концепции, он отличался от других конструкций VLIW и процессоров в целом в ряде конкретных деталей.

Обобщенные функциональные единицы

Большинство процессоров включают в себя ряд отдельных "субпроцессоров", известных как функциональные единицы, которые настроены на работу с определенным типом данных. Например, современный процессор обычно имеет два или три функциональных блока, предназначенных для обработки целых данных и логических инструкций, известных как ALU, в то время как другие блоки обрабатывают числа с плавающей запятой, FPU или мультимедийные данные, SIMD. MAJC вместо этого использовал единую многоцелевую функциональную единицу, которая могла обрабатывать любые данные. Теоретически этот подход означал, что обработка любого типа данных займет больше времени, возможно, намного больше, чем обработка тех же данных в подразделении, предназначенном для этого типа данных. Но с другой стороны, эти универсальные единицы также означали, что вы не закончили с большими частями CPU, не используемыми, потому что программа просто делала много (например) вычислений с плавающей точкой в тот конкретный момент времени.

Инструкционные пакеты переменной длины

Другое отличие заключается в том, что MAJC допускает "пакеты инструкций" с переменной длиной, которые в VLIW содержат ряд инструкций, которые, по определению компилятора, могут быть выполнены одновременно. Большинство архитектур VLIW используют пакеты с фиксированной длиной, и когда они не могут найти инструкцию для выполнения, они вместо этого заполняют ее NOP, которая просто занимает место. Хотя пакеты инструкций с переменной длиной добавляли некоторую сложность процессору, они уменьшали размер кода и, следовательно, количество дорогостоящих пропусках кэша, увеличивая количество кода в кэше в любое время.

Избегание блокировок и задержек

Основным отличием был способ, которым конструкция MAJC требовала от компилятора избегать блокировок, пауз при исполнении, в то время как результаты одной инструкции должны быть обработаны для следующей, чтобы она могла работать. Например, если процессор получает инструкции C = A + B, E = C + D, то вторая инструкция может быть выполнена только после завершения первой. Большинство процессоров включают блокировки в конструкцию, чтобы задерживать и перенастраивать эти виды взаимосвязанных инструкций, позволяя некоторым другим инструкциям запускаться, пока рассчитывается значение C. Однако эти блокировки очень дороги с точки зрения чипа недвижимости, и представляет большинство логики инструкции планировщика. Чтобы компилятор избежал этих блокировок, он должен был бы точно знать, сколько времени потребуется для выполнения каждой из этих инструкций. Например, если конкретная реализация заняла три цикла для завершения умножения с плавающей запятой, компиляторы MAJC попытались бы запланировать в других инструкциях, которые заняли три цикла для завершения и в настоящее время не были приостановлены. Однако изменение в фактической реализации может сократить эту задержку до двух инструкций, и компилятор должен был бы знать об этом изменении. Это означает, что компилятор был связан не с MAJC в целом, а с конкретной реализацией MAJC, каждый отдельный процессор основан на дизайне MAJC. Это обычно было бы серьезной логистической проблемой; например, учитывая количество различных вариантов дизайна Intel IA 32, каждому из них понадобился бы свой собственный выделенный компилятор, и разработчику пришлось бы создать для каждого из них другой двоичный файл. Однако именно эта концепция движет рынком Java - действительно существует разный компилятор для каждой ISA, и он установлен на машине клиента, а не разработчика. Разработчик отправляет только одну байткодную версию своей программы, а машина пользователя компилирует ее на базовую платформу. В действительности, планирование инструкций таким образом оказывается очень сложной проблемой. В реальном мире процессоры, которые пытаются сделать это планирование во время выполнения, сталкиваются с многочисленными событиями, когда необходимые данные находятся вне кэша, и в программе нет другой инструкции, которая не зависит от таких данных. В этих случаях процессор может задерживаться в течение длительного времени, ожидая на главной памяти. Подход VLIW не очень помогает в этом отношении; хотя компилятор может тратить больше времени на поиск инструкций для запуска, это не значит, что он может на самом деле найти одну. MAJC попытался решить эту проблему, предоставив возможность выполнять код из других потоков, если текущий поток застрял в памяти. Переключение потоков обычно является очень дорогим процессом, известным как контекстный переключатель, и на обычном процессоре переключатель будет подавлять любые экономии и обычно замедляет работу машины. В MAJC система могла одновременно хранить состояние до четырех потоков в памяти, сокращая контекстный переключатель до нескольких инструкций в длину. Эта функция с тех пор появилась на других процессорах; Intel называет ее HyperThreading. MAJC пошел на шаг дальше и попытался заранее получить данные и инструкции, необходимые для потоков, пока они были застряли. Большинство процессоров включают в себя аналогичную функциональность для частей потока инструкций, известных как спекулятивное выполнение, где процессор запускает оба возможных результата ветви, ожидая, пока решающая переменная не будет рассчитана. MAJC вместо этого продолжал запускать потоки, как будто они не были задержаны, используя это выполнение для поиска и загрузки любых данных или инструкций, которые вскоре будут необходимы, когда потоки перестанут задерживаться. Sun называет это Space Time Computing (STC), и это спекулятивный многопоточный дизайн. До этого момента процессоры пытались извлечь параллелизм в одной нитке, метод, который достигал своих пределов с точки зрения уменьшающейся отдачи. В общем смысле дизайн MAJC пытался избежать задержек, работая по потокам (и программам), а не искать параллелизм в одном потоке. Ожидается, что VLIW будет несколько хуже с точки зрения задержек, потому что трудно понять поведение во время выполнения во время компиляции, что делает подход MAJC в решении этой проблемы особенно интересным.

Реализация

Sun построила одну модель MAJC, двухядерную MAJC 5200, которая была сердцем графических плат рабочей станции Sun XVR 1000 и XVR 4000. Однако многие из многоядерных и многопоточных дизайнерских идей, особенно с точки зрения использования нескольких потоков для уменьшения задержек задержки, пробились в линию процессоров Sun SPARC, а также в проекты других компаний. Кроме того, идея MAJC о проектировании процессора для запуска как можно большего количества потоков, в отличие от инструкций, кажется основой более позднего дизайна UltraSPARC T1 (кодовое название Niagara).