Комментарии 89
IBM выбирала между 68000 и 8086, но тут появился 8088 с внешней 8 битной шиной, что позволило значительно удешевить материнскую плату и IBM остановила свой выбор на 8088.
P.S. Ну и VLIW красиво походя пнули. Что ответят корифеям фанаты Эльбруса?
Были архитектуры очень экзотические и очень эффективные, но для ограниченного круга задач. Например Сетунь с троичной системой. Или баллистический вычислитель с представлением чисел в виде набора остатков от деления на простые числа. Все это было оттеснено массовостью универсальных процессоров.
Если бы понятие серверов данных, файлов и приложений появились до создания архитектуры массовых процессоров, под них были бы созданы различные высокоэффективные архитектуры, со своими системами команд.
Статья (на английском) «Chuck Moore: Part 2: From Space to GreenArrays»
www.cpushack.com/2013/03/02/chuck-moore-part-2-from-space-to-greenarrays
P.S. Неплохо, для ретро-сравнения и данные этой статьи включить.
А, вот что делалось в те времена и в СССР
«Стековые процессоры, или новое — это хорошо забытое новое»
www.kit-e.ru/articles/cpu/2003_09_98.php
www.kit-e.ru/articles/elcomp/2004_1_102.php (продолжение)
www.kit-e.ru/articles/elcomp/2004_2_130.php (заключение)
Чужие: странная архитектура инопланетных компьютеров
www.ferra.ru/review/techlife/philae-computer.htm
Не всем процессорам и их архитектурам посчастливилось найти своего «массового» потребителя.
F21 in a Mouse www.ultratechnology.com/scope.htm
Чтобы оценить важность этого наблюдения, рассмотрим рисунок 5. Он показывает, насколько быстрее приложение работает с 64 ядрами по сравнению с одним ядром, предположив разную долю последовательных вычислений, когда активен только один процессор. Например, если 1% времени вычисление выполняется последовательно, то преимущество 64-процессорной конфигурации составляет всего 35%.
Не 35% а в 35 раз…
рынок выбрал сделанный впопыпах 8086, а не «помазанника» iAPX-432Такие «истории успеха» весьма показательны.
Правы «зелёные»: «подводной лодке» под названием «планета Земля» дикий размах «экономической самоуправляемости» просто «не по карману».
( Кстати, на вышеупомянутом CPU для ADA вирусы/эксплоиты просто невозможны )
в 62 806 раз быстрее, чем первоначальная Python-версия
Прям обидно, как питон подставили. Для перемножения матриц есть специальные алгоритмы. А они, подозреваю, цикл со сложностью О(n^3) сделали. Разумеется, эти алгоритмы реализованы в виде библиотек на си и фартране, но всё же можно не терять ни капли эффективности работы программиста и при этом получать все плюшки скорости.
Если питон этого не умеет, при чем тут «подставили»?
Нужна не ассемблерная вставка, а, например, алгоритм Штрассена. Несомненно, на питоне тот же самый алгоритм будет медленнее, но на практике вы никогда не будете его реализовывать, независимо от того, на питоне вы пишите или на си. То есть независимо от того, какой язык вы выберете, скорость будет одинакова.
Кстати, если вы на си будете перемножать матрицы наивным циклом, это будет медленнее, чем использование питона + numpy.
То есть на практике, если вы захотите получить ускорение и для этого возьмёте си — вы ускорения не получите. Именно это я и имел ввиду, говоря "подставили". Типа, если нужна скорость, берите си. Но для данной задачи (перемножение матриц) это неверно.
Есть правильный выбор алгоритма. Он от языка не зависит и тут не рассматривается.
Рассматривается только насколько эффективно команды языка высокого уровня превращаются в машинный код. Это зависит от качества компилятора. И от возможностей «понять» смысл кода. Если отказаться от понятия массива в пользу более общей абстракции списка, то доступ к конкретному элементу возможен только стандартным способом и прямая адресация памяти невозможна. Значит компилятор не может заменить обращение к функции получения элемента по номеру на инкремент адреса. Вот и разница больше, чем на порядок.
С, Fortran, Julia — в элитном клубе.
насколько эффективно команды языка высокого уровня превращаются в машинный код
Если 99% времени выполнения занимает вызов библиотеки на фартране, то разница в эффективности трансляции в машинный код между питоном и си несущественна.
Обратите внимание, я не говорю, что нет разницы в скорости между питоном и си — она есть и всем очевидна. Но если кто-то выберет си ради задач по матрицам ради упомянутого в статье прироста в тысячи раз — его ждёт разочарование. Если только он не будет специально писать код как в статье, конечно.
Разговор не о случае, когда есть готовые библиотеки и мы их только вызываем.
Приходилось мне писать такие программы, которые были только специализированной под терминологию заказчика оберткой для стандартной библиотеки. Их действительно все равно на чем писать.
Разница возникает при реализации вычислительных алгоритмов. И тут очень простая зависимость: чем выше уровень абстракции, тем хуже будет результат.
Если язык не пускает тебя к железу, то и оптимизировать не выйдет.
Дональд Кнут: «Предполагалось, что подход Itanium… будет потрясающим — пока не оказалось, что желаемые компиляторы в принципе невозможно написать».А почему? В чём оказалась проблема?
Для меня совершенно не очевидно, почему такая реализация принципиально хуже аппаратного планировщика, как пишет Кнут. Под программным планировщиком я понимаю это код, генерируемый компилятором. Что такое есть в аппаратном планировщике, что нельзя эффективно заменить на программную реализацию в компиляторе? Компилятор может решать, когда логика планировки может быть упрощена или вообще не нужна, если код branching-free.
Вы не можете предсказать следующую команду и соответственно оптимизировать переходы. Предсказатель переходов работает на актуальной для данного времени статистике, а компилятор ее знать заведомо не может и соответственно не может спланировать бранчи.
Предсказатель переходов работает на актуальной для данного времени статистике, а компилятор ее знать заведомо не можетНо может рассмотреть варианты точно так же как это делает хардварный предсказатель. Код хардварного предсказателя можно записать программно.
у компилятора недостаточно тактичекой инфыНо компилятор может сгенерировать код планировщика, который будет учитывать тактическую инфу.
компилятор вынужден принимать безопасные, пессимистичные прогнозы и генерить менее быстрый код,Не обязательно, компилятор может генерировать несколько веток кода, программа может переключаться между ними в зависимости от обстоятельств.
закладываться на слишком много ситуацийАппаратный планировщик действует так же.
генерить лишний код для восстановления из нихКоторый будет лежать в RAM, которой много. Засорения кеша тоже будет, но не факт, что значительное.
компилятор нагенерит лишнего кода, который попадёт в кэш (и сократит его эффективную ёмкость)Но не сильно. Емкость кеша не так сильно влияет на производительность, что видно по тому, что размеры кэша в современных процессорах с одинаковой IPC могут отличаться в разы, без роста производительности. То есть, что бы засорение кэша повлияло на ситуацию без возможности компенсировать простым увеличением его емкости, неэффективность должна отличаться хотя бы в 3 раза, а то и на порядок.
в случае аппаратного планировщика их можно отстрелить на разных стадиях конвейера (когда выполнится только часть команды),А толку? Это может немного снизить энергопотребление, но не производительность, ведь спланировать новую полезную нагрузку скорее всего не получится. Да и программируемный планировщик тоже в принципе может такое, теоретически.
Наконец, аппаратный планировщик способен передавать результаты (разрешать потенциальные зависимости) в ходе выполнения командэто то же самое, что и предыдущий пункт?
Который будет лежать в RAM, которой много. Засорения кеша тоже будет, но не факт, что значительное.Лишнему коду перед исполнением тоже надо будет попасть в кэш (это требует времени и места), значит часть полезного кода может вытесниться, повысится число промахов.
А толку? Это может немного снизить энергопотребление, но не производительностьВы серьезно?) С программным планировщиком вам доступна гранулярность уровня команд, не меньше. С аппаратным — гранулярность уровня тактов, а тактов на команду может быть с десяток и на каждом можно отстрелить лишнее, освободить аппаратный ресурс и занять его другой командой (ну, в теории).
это то же самое, что и предыдущий пункт?Обратите внимание на алгоритм Томасуло. Этот пункт значит, что разрешение зависимостей по данным в случае аппаратного планировщика может происходить гораздо раньше, чем это может позволить программный (потому что гранулярность снова у компилятора не позволяет добраться).
повысится число промахов.Но на сколько? А если увеличить кэш в два-три раза? Предположим, что число веток, которое рассматривает аппаратный планировщик не превышает 2-3 (поправьте, если не так). Значит и оверхед кода для программного планировщика тоже будет 2-3.
С аппаратным — гранулярность уровня тактовВ случае RISC, а тем более VLIW, команда=такт.
тактов на команду может быть с десятокЭта проблема (и её героическое преодоление) существует только для CISC. В случае VLIW проблемы нет.
Обратите внимание на алгоритм ТомасулоОбратил, но не понял, какие существенные недостатки это демонстрирует в случае VLIW процессора, где команда=такт. Более того, на сегодняшний день CISC(Intel, AMD) — это RISC+транслятор CISC->RISC.
RISC processors only use simple instructions that can be executed within one clock cycle.
В случае RISC, а тем более VLIW, команда=такт.Не согласен, у вас там 5-6 тактов на команду, вряд ли меньше, точно не 1, всякие fetch, decode, read operands, execute, write. За один так не уложитесь. В вашей цитате написано про executed, это одна из тех стадий что я привёл, но не единственная.
Но на сколько?Вот опять же не хочу сильно перескакивать, вы вводите дополнительный код, это приводит к увеличению числа промахов, но не только, это приводит к лишним командам, на которые требуется время выполнения, а также к промахам при предсказании ветвлений. Тут бы весь оверхед посчитать, а не только кэш.
Не согласен, у вас там 5-6 тактов на команду, вряд ли меньшеОткуда Ваши данные? Ребята из Стэнфорда пишут, что RISC -> 1instruction=1cycle:
RISC processors only use simple instructions that can be executed within one clock cycle.
это одна из тех стадий что я привёл, но не единственная.Так а что в таком случае мешает программному планировщику задействовать алгоритм Томасуло?
В RISC/VLIW 1 instruction=1cycle, соответственно программный планировщик может оперировать на уровне циклов.
В RISC/VLIW 1 instruction=1cycle
Повторяю: это не так. Ссылку на википедию про конвейер вам ниже дали.
Вот для простоты картинка.
даже не в курсе базовых понятий темы, на которую они спорятЭто Вы про кого ;)?
Повторяю: это не так.видимо, про себя. Наличие конвеера и многостадийность инструкций — вещи вообще никак не связанные. В RISC, в отличии от CISC инструкции однотактовые, но в обоих случаях есть конвеер. А вот у VLIW, о котором и разговор, как раз отличие от RISC в том, что конвеера нет. Вместе с 1цикловостью инструкций это теоретически даёт возможность делать программный планировщик с гранулярностью в 1 cycle.
если многомиллиардная индустрия в лице Intel не справилась с задачей, то вероятно, задача как минимум очень сложнаяЯ в курсе, потому и задал изначальный вопрос, ответ на который мне показался очень неочевидным. О тех аргументах, которые Вы приводите я тоже сначала подумал, но вынужден был их отбросить как несостоятельные, так как сам же нашел у них недостатки. Надеялся, что кто-то мне подскажет аргументы получше.
многомиллиардная индустрия в лице Intel не справилась с задачейС какой задачей? Добиться распространения и коммерческого успеха? Не справилась. Но с технической подзадачей они справились, VLIW процессоры Itanium работали вполне себе неплохо.
В RISC, в отличии от CISC инструкции однотактовые, но в обоих случаях есть конвеер.Как вы себе представляете конвейер для инструкции в 1 такт? Что там конвейеризируется, в чём смысл? Более того, с железячной точки зрения любопытно как за один такт расшифровать инструкцию, запросить и получить операнды, выполнить инструкцию, записать результаты? С какой частотой такое будет работать в железе?
While CISC instructions varied in length, RISC instructions are all the same length and can be fetched in a single operation. Ideally, each of the stages in a RISC processor pipeline should take 1 clock cycle so that the processor finishes an instruction each clock cycle and averages one cycle per instruction (CPI).
processor finishes an instruction each clock cycle
Вот на картинке ниже. Каждый такт processor finishes одну инструкцию. При этом выполнение каждой отдельно взятой инструкции занимает четыре такта. Это если без сбросов и простоев, с ними больше.
Так понятнее, что такое конвейер и почему «одна иструкция за такт» — это не то, о чем вы думаете?
2) Разговор про одну инструкцию за такт начался с вопроса про разную гранулярность аппаратного и программного планировщика.
Аппаратный планировщик имеет гранулярность в один такт, то есть каждый такт смотрит, что происходит со всеми лежащими в конвейере командами, и может принимать решения соответственно.
Для программного планировщика промежуточные результаты выполнения недоступны, поэтому он может сбрасывать конвейер позже, чем смог бы аппаратный, что приводит к значительным потерям в производительности, особенно на сложных ветвящихся алгоритмах, управляемых входными данными.
смотрит, что происходит со всеми лежащими в конвейере командамиВ конверее или на подходе? Он может переставлять стадии уже на выполнении? То есть он может проанализировать ситуацию (составить статистику), принять решение (выбрать ветку), и поменять стадии в конвеере за один цикл?
он может сбрасывать конвейер позже, чем смог бы аппаратныйНо гранулярность такая же, для команд, выполнение которых ещё не началось. Переставлять программный планировщик так же может по одной стадии, только задержка между принятием решения и перестановкой операций = длина конвеера. Если процессор суперскалярный, то есть у нас фактически несколько параллельных конвееров, то на одном из конвееров может крутиться планировщик, если надо.
В RISC, в отличии от CISC инструкции однотактовые, но в обоих случаях есть конвеер.
На «CISC» инструкции такие же «однотактовые» ещё с 486.
www.gamedev.net/articles/programming/general-and-gameplay-programming/a-journey-through-the-cpu-pipeline-r3115
А вот у VLIW, о котором и разговор, как раз отличие от RISC в том, что конвеера нет.
Вы вообще не понимаете о чём пишете.
Конвейер нужен для пресловутой «однотактовости» и разумеется у VLIW он точно такой же.
Несчастный компилятор — это всего лишь программа а не провидец. Вершнинг по условиям внутри цикла у него есть, уже одно это приводило к чрезмерному раздутию кода. Плюс, когда у него не было вариантов забить бандл до полного — это затыкивалось нопами. Еще раздутие кода.
Вообщем там был тихий ужас. Что то простое и прямое, с желательно хорошим флопсом — да, работало. Все остальное, особенно бизнес логика, где нет вычислений но куча условий — не-а… И предикаты спасали лишь отчасти.
Гранулярность программного планировщика тоже = 1 стадия.Не согласен, гранулярность выходит всё равно одна команда. Если считать как вы, получается, что за такт аппаратный планировщик может делать действия с примерно N командами, где N — глубина конвейера. Т.е. его разрешение всё равно выше.
Не знаю, может ли аппаратный планировщик переставлять стадии, которые уже в конвейере.Частичный ответ на этот вопрос есть всё в том же алгоритме Томасуло, обратите внимание на reservation stations.
Т.е. его разрешение всё равно выше.Разрешение не выше, одинаково, оно равно одной стадии. Разница только в том, что аппаратный планировщик может переставлять стадии, которые уже в конвеере, а программный — только те, что ещё не попали в него.
аппаратный планировщик может делать действия с примерно N командами, где N — глубина конвейераПрограммный и аппаратный планировщики могут выполнять действия с любым числом стадий, если эти стадии ещё не на конвейере. Если на конвейере — только аппаратный, видимо.
затем заполнения конвейера командами 2,3,4, которые дождались своего операндаЭто можно сделать за 1 такт, раз аппаратный может. На самом деле там будет иначе. Компилятор запланирует две похожих последовательности команд по разным адресам, а далее одной командой переключит поток с одной последовательности на другую, в зависимости от результатов предыдущей операции.
Компилятор запланирует две последовательности команд по разным адресам, а далее одной командой переключит поток с одной последовательности на другую, в зависимости от результатов предыдущей операции.И результат будет получен через N+ тактов, ведь эти последовательности команд (ту последовательность, которую выбрали) надо будет загрузить в конвейер и выполнить, а это как раз N+ тактов.
И результат будет получен через N+ тактовСогласен, то есть нужно планировать так, что бы смена ветвей была реже чем длина конвейера, что бы конвейеру было чем заняться, пока идёт переключение веток.
надо будет загрузить в конвейер и выполнитьне в конвейер, а в поток исполнения, то есть «перед» конвейером.
то есть нужно планировать так, что бы смена ветвей была реже чем длина конвейераВот где-то в этот момент компиляторы и начинают проигрывать. Реальные алгоритмы не всегда можно вот так разобрать, особенно для VLIW, который постоянно хочет очень много данных. Такая концепция только для числодробилок хорошо работает.
это приводит к лишним командам, на которые требуется время выполненияНо они и так выполняются, просто скрытно, на аппаратном планировщике.
В случае RISC, а тем более VLIW, команда=такт.Вы в курсе, как конвейер работает?
RISC processors only use simple instructions that can be executed within one clock cycle.Это просто неправда. Большинство реализаций RISC-процессоров конвейерные, как минимум с тремя, а чаще с пятью-семью ступенями.
Каждый такт заканчивается выполнение новой команды — это обычно так. Но каждая команда выполняется несколько тактов.
Это просто неправдаМопед не мой, Стэнфордский. Где можно прочитать другую точку зрения?
Each of these classic scalar RISC designs fetched and tried to execute one instruction per cycle.В случае VLIW конвеера не предполагается — «non-pipelined scalar architecture», а значит, можно в любой момент выкинуть инструкцию из потока и заменить другой, на уровне каждого цикла.
Each of these classic scalar RISC designs fetched and tried to execute one instruction per cycle.Еще раз, чтобы вы точно поняли: то, что каждый такт заканчивается выполнение новой инструкции, не означает, что выполнение каждой инструкции длится один такт.
Прочитайте уже, как конвейер устроен, прямо в следующем предложении той статьи в википедии.
Пример кода:
for (day=0; day<3; ++day) {
rain=is_raining(day);
if (rain) wear_waders();
else wear_sneakers();
}
Допустим
is_raining(0)=false
, Аппаратный предсказатель будет «опережая» выполнять wear_sneakers(). Что мешает компилятору сделать такой машинный код:rain0=is_raining(0);
if (rain0) {
for (day=0; day<3; ++day) {
wear_sneakers();
rain=is_raining(day);
if (not rain) { unwear_sneakers(); wear_waders();}
}
else {
...
}
Частоту считать можно точно так же.
может быть результат от аппаратного предсказания ветвлений, т.е. он с большей вероятностью угадает переходПочему? Чем программный предсказатель хуже? Всю тактическую информацию он точно так же может учитывать (алиасинг, кэш...).
введенные ветки занимают место в кэше и требуют времени загрузки в кэш, т.е. уже вносят оверхед.Но много ли? Объем кэша x86 CPU сейчас может различаться в разы без особого роста производительности. То есть при необходимости, в каких-то пределах его можно добавить, если надо.
Почему? Чем программный предсказатель хуже?Ну хотя бы тем, что аппаратный предсказатель работает с текущей ситуацией (например с историей N последних вызовов данного кода), а программный предсказатель использует инфу на этапе компиляции.
Всю тактическую информацию он точно так же может учитывать (алиасинг, кэш...).Ценой введения кучи дополнительных инструкций, которые ударят по производительности (ну серьезно, вы предлагаете ввести много лишнего кода, который надо будет исполнить, почему это должно работать быстро?)
программный предсказатель использует инфу на этапе компиляции.Это не программный предсказатель, это просто компилятор. Программный предсказать выполняется как обычный код, то есть точно так же как и аппаратный предсказатель может динамически считать и учитывать статистику. Отличие в том, что аппаратный предсказатель выполняется на отдельном харде, параллельном ядру и не может менять свою логику, а программный предсказатель выполняется на том же ядре, что и сам полезный код и его логика может меняться на ходу и генерируется компилятором, в соответствии с контекстом, и потому может быть более специальным и эффективным, чем супер-универсальный аппаратный предсказатель.
аппаратный предсказатель выполняется на отдельном харде, параллельном ядру и не может менять свою логикуПочему не может?
А почему? В чём оказалась проблема?VLIW — фирменная «фишка» Эльбрус-2. Далее сплошные «странные» корреляции: лихие девяностые — внезапно появляется IA64, создатель Эльбрусов — лучший почетный работник Intel и т.п.
Поток книг по советскому суперкомпьютеру ( хотя это 1989+ ).
Настал 2008 — «не смогли написать компилятор», эра эвтаназии Itanium.
Совпадения? Не знаю…
Я далек от разработки чипов, так что прошу сильно ногами не бить.
Просто глядя на историю развития процессоров за 30-40 лет, и скорость развития нейросетей и машинного обучения в последние годы, мне кажется это вполне возможным направлением для исследования.
так и сегодня можно встроить отдельный блок, который будет мониторить «трафик» инструкций входящих в процессор и обучать нейросеть
Так предсказатели ветвлений на нейросетях уже несколько лет как серийно применяются. Samsung Exynos 8890 тому пример, прямо в вашем мобильнике.
www.realworldtech.com/jaguar/2
Собственно Самсунг и переманил создателей Jaguar к себе.
Новый золотой век для компьютерной архитектуры