Я понимаю, что память является большим узким местом в современных компьютерных системах, но разве система с большим количеством простых ядер не может быть более эффективной, чем система с однозначным числом продвинутых ядер для некоторых задач?
Насколько я понимаю, GPU — это экстремальная версия этого, но нет ли какой-то золотой середины для определенных задач, требующих плотности/сложности, которая находится где-то между двумя крайностями?
Программирование для параллелизма сложно, поэтому большинство вещей в основном выполняются последовательно, что требует более сложных процессоров. Ограничение тактовой частоты предотвращает усложнение процессоров, поэтому вместо этого у нас есть несколько сложных процессоров, которые в основном позволяют выполнять независимые задачи одновременно или позволяют разделить одну задачу на несколько одновременных потоков, когда это действительно очевидно и просто сделать. так.
Поскольку программирование для параллелизма сложно, вы можете довольно точно предсказать, когда дополнительный массивный параллелизм для усилий будет вложен в программирование (т. е. там, где он действительно необходим). Это позволяет легко определить, кто на самом деле будет заниматься параллельной работой со многими простыми ядрами, поэтому вы получите ЦП общего назначения с меньшим количеством сложных ядер и графические процессоры специального назначения с большим количеством более простых ядер.
Разработка стоит дорого, поэтому вам нужен достаточно большой рынок для поддержки разработки многоядерных процессоров смешанной или средней сложности.
Насколько я понимаю, GPU — это экстремальная версия этого, но нет ли какой-то золотой середины для определенных задач, требующих плотности/сложности, которая находится где-то между двумя крайностями?
Современные графические процессоры — это золотая середина. В то время как более ранние графические процессоры были действительно простыми «одна инструкция, разные данные, все ждут, пока не будет выполнена самая медленная, следующая инструкция» с очень ограниченным набором инструкций, современные вычислительные блоки графических процессоров гораздо более универсальны и независимы.
Было несколько (если не много) попыток сделать это раньше — и, если не считать нишевого использования, все они потерпели неудачу из-за того, что не попали ни в золотую середину независимых высокопроизводительных процессоров, ни в дешевые, маломощные массивно-параллельные упрощенные шейдерные блоки. По сути, вам нужно эффективно использовать как процессорное время, так и пропускную способность памяти, а это означает, что вам нужно либо несколько, но производительных ядер, совместно использующих основную память, но имеющих обширный локальный кэш, либо вам нужно много, но централизованно организованных более простых ядер. Это показало, что вы действительно не можете легко получить и то, и другое — вот (моя интерпретация), почему миру потребовалось так много времени, чтобы прийти к современным графическим процессорам, и почему только две компании очень явно доминируют на рынке GPGPU с одним явным лидером.
Примеры этих коммерческих неудач включают:
¹ Larrabee использовала очень неэффективные ядра x86 в многоядерном процессоре и, таким образом, была промежуточным звеном и бесполезна, уступив место графическим процессорам, с одной стороны, и классическим процессорам для рабочих станций/серверов, с другой, хотя можно утверждать, что его преемник, Xeon Phi, лучшая судьба, но это действительно больше похоже на множество мощных x86-64, включая AVX-512, на одном чипе, так что это не золотая середина, на которую вы надеетесь. Серия была прекращена в прошлом году, в основном из-за отсутствия спроса — графические процессоры, с одной стороны, классические x86-64, с другой стороны, просто более полезны и лучше вычисляют/Ватт.
Я хотел бы принять вызов кадра дальше, чем другие ответы здесь. До конца 20-го века параллельные вычисления были прерогативой специализированных серверов и суперкомпьютеров; потребительские компьютеры общего назначения были основаны на одном ядре процессора, работающем со все более и более высокими тактовыми частотами. С тех пор многоядерные процессоры стали нормой, а количество включенных ядер постепенно увеличивалось.
Современные архитектуры могут включать (даже на одном чипе):
Тем не менее, многие программы могут использовать только одно ядро, поэтому процессорные ядра общего назначения вряд ли исчезнут в ближайшее время. Это потому, что вы можете использовать несколько ядер только в определенных случаях:
Некоторые задачи поддаются параллелизму, некоторые нет. В целом, задачи, которые имеют тенденцию повторяться с большим количеством времени, затрачиваемым на циклы, могут быть разделены на более мелкие подзадачи, маршалируемые хостом. Задачи, которые имеют тенденцию быть «потоковыми» с большим количеством ветвей, не так просто разбить.
Графика и искусственный интеллект — это примеры, которые можно разбить на параллельные задачи. TCP/IP не очень.
Дело в том, что есть место для обоих.
Хм, графические процессоры — это не «экстремальная версия системы с множеством простых ядер». Например, в графическом процессоре Nvidia каждый SM (потоковый мультипроцессор) является многопоточным процессором. Путь данных представляет собой 16 дорожек IIRC, каждая из которых способна выполнять 32-битные вычисления с плавающей запятой. Многопоточное планирование графического процессора намного сложнее, чем планирование для ЦП MT, и, возможно, сравнимо с планированием планировщика OOO ILP.
Большая разница в том, что ЦП ООО должен принимать множество различных решений планирования в каждом цикле, которые влияют на следующие 1-3 цикла. В значительной степени разные решения планирования для каждой инструкции. Принимая во внимание, что решение о планировании GPU применяется к этому набору из 16 ALU в пространстве, а также, как правило, от 2 до 4 тактов в глубину. Более того, вместо того, чтобы планировать зависимую инструкцию на 1 или 2 такта позже, в графическом процессоре следующая зависимая инструкция из того же потока может прибыть только на много тактов позже — в некоторых графических процессорах не ранее, чем через 40 тактов!!!! Между операциями планирования графического процессора группируются другие потоки. Однако все больше и больше даже массивно-параллельных рабочих нагрузок графического процессора не имеют достаточного параллелизма,
Т.е. самая большая разница между ЦП и ГП SM состоит в том, что SM амортизирует стоимость управляющей логики для множества элементов блокировки на поток/деформацию и множество независимых потоков/деформаций потока управления в одном и том же процессоре.
Плюс, конечно, у графического процессора есть несколько таких элементов обработки. В одном чипе гораздо больше возможностей, чем в процессорах.
В целом, GPU имеют гораздо более низкое отношение логики управления к логике вычислений/ALU, чем CPU. Логика управления графическим процессором довольно сложна, но ее стоимость распределяется, амортизируется, по большему количеству ALU, потому что в графическом процессоре многие из ALU делают почти одно и то же в одно и то же время.
—
Но я не обращаюсь к вашему вопросу, не так ли? Вы спросили «почему не много простых процессоров, а не больших сложных одиночных процессоров…»?
Название «множество независимых процессоров» — MIMD. Несколько инструкций Mujtiple Data». Итак, GPU — это MIMD, но каждый из его независимых процессоров — это SIMD lockstep и многопоточность MT.
Я думаю, вы спрашиваете о «множестве независимых простых процессоров». MIMD, чьи независимые процессоры, скажем, чернильные 32 или 64-битные, не многопоточные, не suoerscakar и не ООО. Мне нравится называть это MIMD(1), тогда как GPU — это MIMD(SIMD(16x2)*MT(…))
Итак: вот где GPU превосходит MIMD-1 — MIMD-1 имеет как минимум в 16 раз больше управляющей логики, пропорционально, чем простой GPU MIMd(SIMD(32)), даже если предположить, что ядра GPZu не являются MT или ILP. . Т.е. GPU тратит только 1/16 площади и мощности на управляющую логику, чем MIMD-1.
---
Но опять же, вы не спрашиваете, почему GPU превосходит массивно-параллельный MIMD-1. Вы спрашиваете, почему массивно-параллельная машина с простыми элементами обработки MIMD-1 не побеждает машину, чьи элементы обработки намного сложнее. Возможно, 16 или 1024x сложнее, так что у вас может быть только 1/16 - 1/1024, если процессоры. Скажем, «всего» 8 ЦП на чип, а не 128 или даже 8 тыс. MIMD-1 в одном чипе.
Что ж, MPP-MIMD-1 превзойдет машину с гораздо более сложными ядрами — точно для тех же рабочих нагрузок, в которых GPU превосходит машину MIMD-1. Таким образом, MIMD-1 выдавливается.
А для других рабочих нагрузок… ну, если не хватает параллелизма, чтобы использовать все простые процессоры MIMD-1, его побеждают большие процессоры. И даже если параллелизма достаточно, но если нерегулярный вид, с которым GPU не справляются - ну тогда ядра MIMD-1, вероятно, тратят много времени на ожидание памяти.
Кроме того, если на то пошло, если у вас в 16 раз больше процессоров MIMD-1, чем у вас больших процессоров, у вас в 16 раз больше проводов, идущих к памяти. Что сводит на нет предполагаемое 16-кратное преимущество.
Например, MPP MIMD-1 превзойдет менее параллельную машину с большим процессором в рабочей нагрузке с достаточным параллелизмом, если бы память была свободна, задержка в 1 такт и если бы провода памяти ничего не стоили. Или, что то же самое, если бы каждый из MIMD-1 обращался только к частной памяти. Если бы логические элементы были намного больше, чем провода… но когда площадь проводки и мощность доминируют над фактической логикой, MIMD-1 теряют все больше и больше земли из-за меньшего количества параллельных больших процессоров.
---
Возможно, еще есть место для MPP MIMD-1, но оно зажато между графическими процессорами и большими процессорами без графических процессоров.
---
Вот вам и плохие новости. Теперь о хороших новостях:
Программисты предпочитают думать о полностью независимых процессорах MIMD, чем думать о сложных компромиссах между MIMD, SIMD и MT.
Фактически, историческая модель программирования графического процессора заключалась в том, чтобы рассматривать каждый из потоков дорожки блокировки в рамках деформации потока управления как независимый MIMD-1.
И наоборот, другая модель программирования, с которой люди кажутся удобными, — это один поток управления, но с параллельными операциями с данными, такими как работа с произвольными массивами. По сути, векторный процессор. Но опять же, людям нравятся произвольные векторы и массивы, и им не нравится беспокоиться о настройке на разное количество векторных элементов и т. д.
Во многих отношениях GPU — это просто способ взять код MIMD-1 и запустить его в менее дорогой микроархитектуре, которая разделяет логику управления между тем, что в противном случае было бы независимыми элементами обработки.
Т. е. хорошая новость заключается в том, что ваша модель «много простых процессоров» выигрывает в некоторых областях, но как концепция программного обеспечения или модели программирования, которую мы реализуем более эффективно либо с помощью графического процессора, либо с меньшим количеством параллельных, но с большим количеством микроархитектур ILP/MLP.
Алгоритмы, доказательства, мыслительные процессы, как правило, представляют собой список последовательных действий. Человеческий мозг может быть массивным параллельным процессором, но то, что он делает параллельно, — это не столько сознательные мыслительные процессы, сколько приобретенные навыки. Как следствие, описания того, что компьютер должен делать, имеет тенденцию быть структурированным сравнительно линейным образом, а наборы компьютерных инструкций структурированы в виде последовательных шагов, а не набора задач, которые должны выполняться с некоторой взаимозависимостью. Суперскалярные архитектуры на самом деле распараллеливают несколько вещей при выяснении взаимозависимости, а в исходной архитектуре MIPS («микропроцессор без взаимосвязанных этапов конвейера») компилятор уже вычислял эти взаимозависимости и соответствующим образом планировал операции.
Но это в очень незначительном и очень низкоуровневом масштабе. Оказывается, что последовательность очень сильно пронизывает вычисления, размышления о вычислениях и программировании, и попытки массивного параллелизма, разумно выраженные естественным образом в архитектуре («архитектура потока данных») и/или программировании («Оккам»), на самом деле не взлетели, и некоторые массово распараллеливаемые такие системы, как искусственные нейронные сети, получают свое программирование скорее посредством взмахов руками и «обучения», а не явных инструкций.
TL:DR: Да, но не для большинства задач. Вот почему текущая итерация этой идеи — это гибридные процессоры с некоторой производительностью, некоторыми ядрами эффективности, теперь, когда у нас есть транзисторные бюджеты, чтобы добавить столько ядер в потребительский ноутбук / настольный процессор.
но разве система со многими простыми ядрами не может быть более эффективной, чем система с однозначным числом продвинутых ядер для некоторых задач?
"Для некоторых задач" - это загвоздка. Они намного хуже для многих других задач, которые не были или не могут быть легко распараллелены. Например, для зацикливания массива среднего размера часто не стоит говорить с другими ядрами ЦП о выполнении части работы, потому что связанная с этим задержка сравнима со временем, которое потребовалось бы просто для выполнения работы в одном потоке.
И процессор «многие простые процессоры» хуже, чем графические процессоры, для задач, которые очень параллельны и не имеют большого количества зависимых от данных ветвлений. То есть там, где можно допустить высокую задержку для достижения высокой пропускной способности на единицу мощности и площади кристалла, которую могут обеспечить графические процессоры. Итак, как указывалось в других ответах, золотая середина между графическими процессорами с оптимизированной пропускной способностью и процессорами с оптимизированной задержкой не очень велика с точки зрения коммерческого спроса. (Такие вещи, как CPU SIMD, делают это достаточно хорошо для большинства задач, хотя с учетом того, что энергоэффективность становится все более важной, остается место для гибридных процессоров с некоторыми эффективными ядрами.)
Производительность на поток очень важна для вещей, которые не являются смущающе параллельными. (А также потому, что пропускная способность памяти/кэш-память масштабируются в зависимости от количества потоков для многих рабочих нагрузок, поэтому существует нижний предел того, насколько простым/маленьким вы хотели бы сделать каждое ядро без совершенно другой архитектуры, такой как графический процессор.)
Система с меньшим количеством больших ядер может использовать SMT (одновременная многопоточность , например, гиперпоточность), чтобы эти большие ядра выглядели как в 2 раза больше меньших ядер. (Или 4x или 8x, например, в процессорах IBM POWER.) Это не так эффективно, как наличие большего количества ядер меньшего размера, но находится на том же уровне. И, конечно же, простое переключение контекста ОС позволяет запускать на ядре столько программных потоков, сколько вы хотите, в то время как обратное невозможно: нет простого способа использовать множество простых ядер для быстрой работы одного потока.
Есть убывающая отдача Противоположность этому вопросу: почему бы не сделать одно большое ядро ЦП? имеет
Связанный: Современные микропроцессоры 90-минутное руководство! содержит раздел, посвященный SMT и многоядерным процессорам, а также является отличным справочным пособием по конструктивным ограничениям ЦП, таким как мощность.
Создание больших систем, когерентных с кешем, сложно, поэтому их трудно масштабировать до огромного количества ядер ЦП. Самые большие чипы Xeon и Epyc содержат 56 или 64 физических ядра на одном кристалле.
Сравните это с вычислительными картами Xeon Phi , и это в значительной степени то, о чем вы задавались вопросом: AVX-512 крепится к маломощным ядрам Silvermont, увеличивая до 72 ядер на карту с некоторой памятью с высокой пропускной способностью. (И 4-сторонний SMT, чтобы скрыть задержку ALU и памяти, поэтому он фактически поддерживал в 4 раза больше потоков.)
Они прекратили выпуск этой линии в 2018 году из-за отсутствия спроса. Эта статьяговорит, что «никогда не видел коммерческого успеха на рынке». Вы не могли бы получить большое ускорение от запуска на нем существующих двоичных файлов; код, как правило, необходимо было скомпилировать, чтобы воспользоваться преимуществами AVX-512. (Я думаю, что инструментальная цепочка Intel должна была иметь возможность автоматически распараллеливать некоторые циклы, поэтому изменения исходного кода могли быть менее необходимыми или меньшими, чем при использовании графических процессоров). И в нем не было AVX-512BW, поэтому он не подходил для высококачественного кодирования видео (x264/x265 в отличие от аппаратного обеспечения с фиксированными функциями); Я думаю, в первую очередь хорошо для работы FP, что означает, что он конкурирует с графическими процессорами. (Отчасти это может быть связано с работой над новой архитектурой для «экзафлопсных» вычислений, после наблюдения за тем, как развивался вычислительный ландшафт с момента запуска проекта Larrabee в середине 2000-х;
Последняя итерация вашей идеи состоит в том, чтобы иметь сочетание ядер, поэтому у вас все еще может быть несколько быстрых ядер для последовательных / чувствительных к задержке вещей.
Некоторый код лишь частично параллелен или имеет несколько разных потоков, выполняющих отдельные задачи, которые по отдельности являются последовательными. (На самом деле не распределяя одну задачу по многим потокам.)
ARM занимается этим некоторое время (называя это big.LITTLE), и новый дизайн Intel Alder Lake с сочетанием ядер Performance (Golden Cove) и Efficiency (Gracemont) именно таков: добавьте несколько относительно небольших оптимизированных по пропускной способности ядра, которые не заходят так далеко в убывающую отдачу, тратя больше энергии на увеличение пропускной способности на поток.
Таким образом, при выполнении «легковесной» работы, когда E-ядра достаточно, чтобы не отставать от чего-то, что бесполезно делать быстрее (например, воспроизведение видео или набор текста / щелчок по веб-странице), требуется только это маленькое ядро. быть включенным.
Или при обработке чисел/кодировании видео/что-то еще с большим количеством параллелизма на уровне потоков, 4 E-ядра на площади одного P-ядра дают вам большую общую пропускную способность. Но у вас все еще есть несколько P-ядер для задач, которые не распараллелены (или просто не были). (Более подробно про Олдер Лейк я писал на superuser.com .)
Даже ядра E на Alder Lake выполняют довольно широкое суперскалярное выполнение вне очереди и могут иметь довольно хорошую пропускную способность в коде, где ЦП легко найти параллелизм на уровне инструкций. (В ARM big.LITTLE маленькие ядра часто располагаются по порядку, но все же имеют суперскалярную структуру 3 ширины с такими вещами, как кеш-память с попаданием при промахе, чтобы найти некоторый параллелизм на уровне памяти. Например, Cortex-A53)
Для большинства систем с общими рабочими нагрузками коммерчески невыгодно не иметь ядер с оптимизированной задержкой, которые обладают высокой однопоточной производительностью. Многие задачи не могут быть легко распараллелены или просто не распараллелены, потому что это требует гораздо больше усилий при программировании. (Хотя в недорогих смартфонах иногда используются только низкопроизводительные ядра; люди предпочли бы дешевый и медленный телефон, а не отсутствие телефона вообще, а энергоэффективность имеет даже большее значение, чем для ноутбуков.)
Я уже упоминал Xeon Phi, но за несколько лет до этого другим интересным примером был Sun UltraSPARC T1 , он же Niagara, выпущенный в 2005 году.
Это был 8-ядерный ЦП (или 4- или 6-ядерный для других моделей) в то время, когда процессоры x86 только начинали выпускать двухъядерные процессоры, такие как Athlon X2 . Они даже не стремились к высокой производительности для каждого потока, что в то время было необходимо для интерактивного использования. Вместо этого они стремились к рабочим нагрузкам сервера/базы данных с большим количеством подключений, поэтому уже тогда было много параллелизма на уровне потоков для программного обеспечения.
Каждое ядро имело довольно простой конвейер и представляло собой «барабанный» процессор, вращающийся между 4 не остановившимися логическими ядрами, также известными как аппаратные потоки. (В основном, как 4-процессорный SMT, но в таком порядке, чтобы инструкции из отдельных потоков никогда не смешивались в исполнительном блоке.) Я думаю, что сохранение небольших и простых ядер уменьшило накладные расходы на блокировку.
32 логических ядра были огромным количеством в 2005 году (а более поздние поколения были способны работать с несколькими сокетами, что позволяло в 2 или 4 раза больше во всей системе). В вики-статье упоминается, что без специальных опций компилятора (как я полагаю, для автоматического распараллеливания) он оставил большую часть производительности для рабочих нагрузок, которые еще не были распараллелены, например, или MySQL (еще в 2005 году, и IDK, gzip
если они говорили про один большой запрос или что). Так что это обратная сторона наличия большого количества слабых ядер, особенно если вы действительно опираетесь на это, как это сделала Sun, делая его с небольшим объемом кэш-памяти и в зависимости от процессора ствола, чтобы скрыть задержку.
Сноска 1 : Частично это было связано с тем, что большая часть рынка x86 предназначалась для машин, которые будут работать под управлением Windows, и до Windows XP основные версии не поддерживали SMP IIRC. Но серверы долгое время были многосокетными , достигая SMP за счет размещения нескольких физических пакетов ЦП в отдельных сокетах. Но в первую очередь это было связано с тем, что бюджеты транзисторов все еще находились на уровне, когда больший объем кэш-памяти и более широкое/глубокое выполнение OoO по-прежнему давали значительный выигрыш.
Связь между ядрами всегда будет довольно дорогой (по крайней мере, с высокой задержкой), потому что расстояния по своей сути велики, а также из-за неправильного выполнения, чтобы скрыть задержку памяти и кэша L3. Ядро может спекулятивно видеть свои собственные действия, но хранилища нельзя сделать спекулятивно видимыми для других ядер, иначе вам придется откатывать их при обнаружении неверного предсказания ветвления. (Что совершенно нецелесообразно с точки зрения поддержания согласованной точки для отката и противоречит цели создания отдельного ядра.)
Таким образом, межъядерная связь занимает как минимум задержку протокола межсоединения и кэш-когерентности, а также задержку буфера хранилища и неупорядоченного окна выполнения. (И обычно используемые барьеры упорядочения памяти несколько ограничивают выполнение не по порядку.)
тобальт
пользователь_1818839
Миту Радж
Йорг В. Миттаг
Сайед