Цен­траль­ный про­цес­сор (ЦП) часто назы­ва­ют моз­гом ком­пью­те­ра, и так же, как и чело­ве­че­ский мозг, он состо­ит из несколь­ких частей, кото­рые рабо­та­ют вме­сте для обра­бот­ки инфор­ма­ции. Есть части, кото­рые при­ни­ма­ют инфор­ма­цию, части, кото­рые хра­нят инфор­ма­цию, части, кото­рые обра­ба­ты­ва­ют инфор­ма­цию, части, кото­рые помо­га­ют выво­дить инфор­ма­цию, и мно­гое дру­гое. В этом мате­ри­а­ле мы рас­смот­рим клю­че­вые эле­мен­ты, из кото­рых состо­ит про­цес­сор, и то, как они все вме­сте рабо­та­ют.

Как работает процессор вашего компьютера?

Важ­но пони­мать, что эта ста­тья неиз­беж­но будет иметь мно­гой абстрак­ций. Когда вы смот­ри­те внутрь чего-то вро­де бло­ка пита­ния, вы чет­ко види­те кон­ден­са­то­ры, транс­фор­ма­то­ры и дру­гие ком­по­нен­ты. В слу­чае с совре­мен­ным про­цес­со­ром это про­сто невоз­мож­но, так как все настоль­ко кро­шеч­но и пото­му, что Intel и AMD не рас­кры­ва­ют пуб­лич­но свои элек­трон­ные схе­мы. Боль­шин­ство мик­ро­схем ЦП явля­ют­ся про­при­е­тар­ны­ми, поэто­му темы, рас­смот­рен­ные в этой ста­тье, пред­став­ля­ют общие воз­мож­но­сти, кото­ры­ми обла­да­ют все ЦП на сего­дняш­ний день.

Что ж, при­сту­пим к погру­же­нию. Каж­дая циф­ро­вая систе­ма нуж­да­ет­ся в какой-то фор­ме цен­траль­но­го про­цес­со­ра. По сути, про­грам­мист пишет код, что­бы выпол­нить свою зада­чу, а затем про­цес­сор выпол­ня­ет этот код, что­бы полу­чить жела­е­мый резуль­тат. ЦП так­же под­клю­ча­ет­ся к дру­гим частям систе­мы, таким как память и систе­мы ввода/вывода, что­бы обес­пе­чить пере­да­чу соот­вет­ству­ю­щих дан­ных, но сего­дня мы не будем их рас­смат­ри­вать.

Архитектура набора инструкций (ISA)

При ана­ли­зе любо­го про­цес­со­ра, пер­вое, с чем вы столк­не­тесь, это с архи­тек­ту­рой набо­ра инструк­ций (ISA). Это схе­ма того, как рабо­та­ет ЦП и как все внут­рен­ние систе­мы вза­и­мо­дей­ству­ют друг с дру­гом. Точ­но так же, как суще­ству­ет мно­же­ство пород собак внут­ри одно­го вида, суще­ству­ет мно­же­ство раз­лич­ных типов ISA, на кото­рых может быть постро­ен ЦП. Дву­мя наи­бо­лее рас­про­стра­нен­ны­ми архи­тек­ту­ра явля­ют­ся x86 (встре­ча­ет­ся в настоль­ных ком­пью­те­рах и ноут­бу­ках) и ARM (встре­ча­ет­ся в мобиль­ных устрой­ствах).

Есть и дру­гие, более ред­кие типы, такие как MIPS, RISC‑V и PowerPC. ISA ука­жет, какие инструк­ции может обра­ба­ты­вать про­цес­сор, как он вза­и­мо­дей­ству­ет с памя­тью и кэшем, как раз­де­ле­на рабо­та на мно­гие ста­дии обра­бот­ки и мно­гое дру­гое.

Что­бы опи­сать основ­ные части про­цес­со­ра, мы будем сле­до­вать по пути, по кото­ро­му выпол­ня­ет­ся инструк­ция. Раз­лич­ные типы инструк­ций могут идти раз­ны­ми путя­ми и исполь­зо­вать раз­ные части про­цес­со­ра, но мы будем ста­рать­ся обоб­щать, охва­ты­вая в первую оче­редь самые зна­чи­тель­ные части. Мы нач­нем с само­го базо­во­го дизай­на одно­ядер­но­го про­цес­со­ра и посте­пен­но будем добав­лять слож­ность по мере того, как будем дви­гать­ся к более совре­мен­но­му дизай­ну.

Блок управления и блок передачи данных (datapath)

ЦП мож­но раз­де­лить на две части: блок управ­ле­ния и блок пере­да­чи дан­ных (datapath). Пред­ставь­те себе вагон поез­да. Дви­га­тель – это то, что дви­жет поез­дом, но про­вод­ник тянет рыча­ги за кули­сы и управ­ля­ет раз­лич­ны­ми аспек­та­ми рабо­ты дви­га­те­ля. Про­цес­сор – это то же самое.

Блок пере­да­чи дан­ных, как сле­ду­ет из назва­ния, явля­ет­ся путем, по кото­ро­му дан­ные текут по мере их обра­бот­ки. Он при­ни­ма­ет вход­ные дан­ные, обра­ба­ты­ва­ет их и отправ­ля­ет в нуж­ное место, когда они закон­че­ны. Блок управ­ле­ния сооб­ща­ет бло­ку пере­да­чи дан­ных, как дей­ство­вать подоб­но про­вод­ни­ку поез­да. В зави­си­мо­сти от инструк­ции блок пере­да­чи дан­ных будет направ­лять сиг­на­лы к раз­лич­ным ком­по­нен­там, вклю­чать и выклю­чать раз­лич­ные части и кон­тро­ли­ро­вать состо­я­ние про­цес­со­ра.

Как работает процессор вашего компьютера?

Блок-схе­ма стан­дарт­но­го про­цес­со­ра. Чер­ные линии ука­зы­ва­ют на поток дан­ных, крас­ные – на управ­ля­ю­щий поток. Автор иллю­стра­ции Lambtron

Цикл исполнения инструкций: стадия Fetch

Пер­вое, что дол­жен сде­лать наш про­цес­сор, это выяс­нить, какие инструк­ции выпол­нить даль­ше, и пере­не­сти их из памя­ти в про­цес­сор. Инструк­ции созда­ют­ся ком­пи­ля­то­ром и спе­ци­фич­ны для ISA про­цес­со­ра. ISA име­ет наи­бо­лее рас­про­стра­нен­ные типы инструк­ций, такие как загруз­ка, хра­не­ние, добав­ле­ние, вычи­та­ние и т.д., но суще­ству­ет мно­же­ство допол­ни­тель­ных спе­ци­аль­ных типов инструк­ций, уни­каль­ных для каж­до­го кон­крет­но­го ISA. Блок управ­ле­ния будет знать, какие сиг­на­лы долж­ны быть направ­ле­ны и куда для каж­до­го типа инструк­ций.

Когда вы запус­ка­е­те .exe, напри­мер, под Windows, код этой про­грам­мы пере­ме­ща­ет­ся в память, и про­цес­со­ру сооб­ща­ет­ся, по како­му адре­су начи­на­ет­ся пер­вая инструк­ция. ЦП все­гда ведет внут­рен­ний регистр, в кото­ром хра­нит­ся ячей­ка памя­ти со сле­ду­ю­щей выпол­ня­е­мой инструк­ци­ей. Он назы­ва­ет­ся “Счет­чик команд”.

Как толь­ко он узна­ет, с чего начать, пер­вым шагом цик­ла обра­бот­ки инструк­ций явля­ет­ся полу­че­ние этой инструк­ции. Это пере­ме­ща­ет инструк­цию из памя­ти в регистр команд ЦП и назы­ва­ет­ся ста­ди­ей Fetch (сбор­ка). В реаль­но­сти, ско­рее все­го, инструк­ция уже нахо­дит­ся в кэше ЦП, но мы рас­смот­рим эти дета­ли немно­го поз­же.

Цикл исполнения инструкций: стадия Decode

Когда у ЦП есть инструк­ция, ему необ­хо­ди­мо выяс­нить, какой это тип инструк­ции. Это назы­ва­ет­ся ста­ди­ей деко­ди­ро­ва­ния (Decode). Каж­дая инструк­ция будет иметь опре­де­лен­ный набор битов, назы­ва­е­мый Opcode, кото­рый гово­рит про­цес­со­ру, как ее интер­пре­ти­ро­вать. Это похо­же на то, как раз­лич­ные рас­ши­ре­ния фай­лов исполь­зу­ют­ся для ука­за­ния ком­пью­те­ру, как интер­пре­ти­ро­вать файл. Напри­мер, .jpg и .png явля­ют­ся фай­ла­ми изоб­ра­же­ний, но они хра­нят дан­ные по-раз­но­му, поэто­му ком­пью­те­ру необ­хо­ди­мо знать тип, что­бы пра­виль­но интер­пре­ти­ро­вать и отоб­ра­зить их.

В зави­си­мо­сти от того, насколь­ко сло­жен ISA, часть про­цес­со­ра, пред­на­зна­чен­ная для рас­шиф­ров­ки инструк­ций, может ока­зать­ся более слож­ной. Такой ISA, как RISC‑V, может иметь все­го несколь­ко десят­ков инструк­ции, в то вре­мя как x86 име­ет тыся­чи. На типич­ном про­цес­со­ре Intel x86 про­цесс деко­ди­ро­ва­ния явля­ет­ся одним из самых слож­ных и зани­ма­ет мно­го места. Наи­бо­лее рас­про­стра­нен­ны­ми типа­ми инструк­ций, кото­рые про­цес­сор будет деко­ди­ро­вать, явля­ют­ся инструк­ции памя­ти, ариф­ме­ти­ки или пере­хо­да.

3 основных типа инструкций

Инструк­ция памя­ти может быть как “счи­тать зна­че­ние из адре­са памя­ти 1234 в зна­че­ние A”, так и “запи­сать зна­че­ние B в адрес памя­ти 5678”. Ариф­ме­ти­че­ская коман­да может быть как “доба­вить зна­че­ние A к зна­че­нию B и запи­сать резуль­тат в зна­че­ние C”. Инструк­ция пере­хо­да может быть чем-то вро­де “выпол­нить этот код, если зна­че­ние С поло­жи­тель­ное, или выпол­нить этот код, если зна­че­ние С отри­ца­тель­ное”. Типич­ная про­грам­ма может собрать их в цепоч­ку, что­бы при­ду­мать что-то вро­де “доба­вить зна­че­ние по адре­су памя­ти 1234 к зна­че­нию по адре­су памя­ти 5678 и запи­сать его в память по адре­су 4321, если резуль­тат поло­жи­тель­ный, или по адре­су 8765, если резуль­тат отри­ца­тель­ный”.

Перед тем, как мы нач­нем выпол­нять толь­ко что рас­шиф­ро­ван­ную инструк­цию, нам нуж­но спер­ва пого­во­рить о реги­страх.

В про­цес­со­ре есть несколь­ко очень малень­ких, но очень быст­рых кус­ков памя­ти, назы­ва­е­мых реги­стра­ми. На 64-бит­ном про­цес­со­ре они будут вме­щать по 64 бита и для ядра их может быть все­го несколь­ко десят­ков. Они исполь­зу­ют­ся для хра­не­ния зна­че­ний, кото­рые исполь­зу­ют­ся в насто­я­щее вре­мя и могут рас­смат­ри­вать­ся как что-то вро­де кэша нуле­во­го уров­ня (L0). В при­ве­ден­ных выше при­ме­рах инструк­ций зна­че­ния A, B и C будут хра­нить­ся в реги­страх.

Арифметико-логическое устройство (АЛУ)

Воз­вра­ща­ем­ся к ста­дии испол­не­ния. Для 3‑х типов инструк­ций, о кото­рых мы гово­ри­ли выше, все будет по-раз­но­му, поэто­му мы рас­смот­рим каж­дую инструк­цию отдель­но.

Нач­нем с ариф­ме­ти­че­ских инструк­ций, так как они самые про­стые для пони­ма­ния. Эти типы инструк­ций пода­ют­ся в ариф­ме­ти­ко-логи­че­ское устрой­ство для обра­бот­ки. АЛУ – это схе­ма, кото­рая обыч­но при­ни­ма­ет два вхо­да с управ­ля­ю­щим сиг­на­лом и выво­дит резуль­тат.

Как работает процессор вашего компьютера?

Пред­ставь­те себе каль­ку­ля­тор, кото­рый вы исполь­зо­ва­ли в сред­ней шко­ле. Для выпол­не­ния опе­ра­ции вы вво­ди­те два вход­ных зна­че­ния, а так­же тип опе­ра­ции, кото­рую вы хоти­те выпол­нить. Каль­ку­ля­тор про­из­во­дит вычис­ле­ния и выво­дит резуль­тат. В слу­чае с АЛУ наше­го про­цес­со­ра, тип опе­ра­ции опре­де­ля­ет Opcode инструк­ции, и блок управ­ле­ния отпра­вит его на АЛУ. В допол­не­ние к базо­вой ариф­ме­ти­ке, АЛУ могут выпол­нять и бито­вые опе­ра­ции типа AND, OR, NOT и XOR. АЛУ так­же выдаст бло­ку управ­ле­ния неко­то­рую инфор­ма­цию о состо­я­нии толь­ко что выпол­нен­но­го вычис­ле­ния. Это может вклю­чать в себя инфор­ма­цию о том, был ли резуль­тат поло­жи­тель­ным, отри­ца­тель­ным, нуле­вым или имел пере­пол­не­ние.

АЛУ боль­ше все­го ассо­ци­и­ру­ет­ся с ариф­ме­ти­че­ски­ми опе­ра­ци­я­ми, но может так­же исполь­зо­вать­ся для инструк­ций в памя­ти или в вет­ках. Напри­мер, ЦП может пона­до­бить­ся вычис­лить адрес памя­ти, задан­ный в резуль­та­те преды­ду­щей ариф­ме­ти­че­ской опе­ра­ции. Так­же может потре­бо­вать­ся вычис­лить сме­ще­ние для добав­ле­ния в счет­чик команд того, что тре­бу­ет инструк­ция пере­хо­да. Что-то вро­де “если преды­ду­щий резуль­тат был отри­ца­тель­ным, пры­гай­те впе­ред на 20 инструк­ций”.

Инструкция памяти и иерархия

Для инструк­ции памя­ти, нам нуж­но понять кон­цеп­цию, кото­рая назы­ва­ет­ся “Иерар­хия памя­ти”. Она пред­став­ля­ет собой отно­ше­ние меж­ду кэшем, опе­ра­тив­ной памя­тью и основ­ным хра­ни­ли­щем. Когда про­цес­сор полу­ча­ет инструк­цию памя­ти для части дан­ных, кото­рую он еще не име­ет локаль­но в сво­их реги­страх, он пой­дет по иерар­хии памя­ти до тех пор, пока не най­дет ее. Боль­шин­ство совре­мен­ных про­цес­со­ров содер­жат три уров­ня кэша: L1, L2 и L3. Пер­вое место, где про­цес­сор будет про­ве­рять – кэш L1. Это самый малень­кий и быст­рый из трех уров­ней кэша. Кэш L1 обыч­но раз­би­ва­ет­ся на пор­цию для дан­ных и пор­цию для инструк­ций. Помни­те, что инструк­ции нуж­но извле­кать из памя­ти так же, как и дан­ные.

Типич­ный кэш L1 может состав­лять несколь­ко сотен КБ. Если про­цес­сор не может най­ти то, что он ищет в кэше L1, он про­ве­рит кэш L2. Это может быть поряд­ка несколь­ких мега­байт. Сле­ду­ю­щим шагом явля­ет­ся L3 кэш, кото­рый может быть несколь­ко десят­ков мега­байт. Если про­цес­сор не может най­ти нуж­ные ему дан­ные в L3 кэше, он перей­дет в опе­ра­тив­ную память и, нако­нец, в основ­ное хра­ни­ли­ще. С каж­дым шагом доступ­ное про­стран­ство уве­ли­чи­ва­ет­ся при­мер­но на поря­док, но так­же уве­ли­чи­ва­ет­ся и вре­мя ожи­да­ния.

Как работает процессор вашего компьютера?

Как толь­ко про­цес­сор най­дет дан­ные, он выве­дет их в иерар­хию, что­бы в буду­щем, при необ­хо­ди­мо­сти, про­цес­сор имел к ним быст­рый доступ. Здесь есть мно­го шагов, но это гаран­ти­ру­ет, что про­цес­сор будет иметь быст­рый доступ к необ­хо­ди­мым дан­ным. Напри­мер, про­цес­сор может читать из сво­их внут­рен­них реги­стров все­го за один или два цик­ла, L1 – за горст­ку цик­лов, L2 – за десять или око­ло того цик­лов, а L3 – за несколь­ко десят­ков. Если ему пона­до­бит­ся обра­тить­ся к памя­ти или к основ­но­му хра­ни­ли­щу, то это может занять десят­ки тысяч или даже мил­ли­о­ны цик­лов. В зави­си­мо­сти от систе­мы, каж­дое ядро, ско­рее все­го, будет иметь свой лич­ный кэш L1, сов­мест­но исполь­зо­вать L2 с дру­гим ядром, и сов­мест­но исполь­зо­вать L3 с груп­па­ми из четы­рех и более ядер. Подроб­нее о мно­го­ядер­ных про­цес­со­рах мы пого­во­рим поз­же в этой ста­тье.

Инструкции перехода и прыжков

Послед­ним из трех основ­ных типов инструк­ций явля­ет­ся инструк­ция пере­хо­да. Совре­мен­ные про­грам­мы посто­ян­но “пры­га­ют” вокруг, и про­цес­сор ред­ко выпол­ня­ет более дюжи­ны смеж­ных инструк­ций без пере­хо­дов. Инструк­ции пере­хо­да исхо­дят от таких эле­мен­тов про­грам­ми­ро­ва­ния, как if-состо­я­ния, for-цик­лы и return-состо­я­ния. Все они исполь­зу­ют­ся для пре­ры­ва­ния выпол­не­ния про­грам­мы и пере­клю­че­ния на дру­гую часть кода. Так­же суще­ству­ют инструк­ции прыж­ков, кото­рые явля­ют­ся инструк­ци­я­ми пере­хо­да, кото­рые все­гда выпол­ня­ют­ся.

Услов­ные пере­хо­ды осо­бен­но слож­ны для про­цес­со­ра, посколь­ку он может выпол­нять сра­зу несколь­ко инструк­ций и не может опре­де­лить резуль­тат рабо­ты пере­хо­да до тех пор, пока не запу­стит­ся по после­ду­ю­щим инструк­ци­ям.

Для того, что­бы пол­но­стью понять, поче­му это про­бле­ма, нам нуж­но будет еще раз отвлечь­ся и пого­во­рить о вычис­ли­тель­ных кон­вей­е­рах. Каж­дый шаг в оче­ре­ди инструк­ций может занять несколь­ко цик­лов. Это озна­ча­ет, что во вре­мя извле­че­ния (Fetch) инструк­ции, АЛУ может сидеть без дела. Что­бы уве­ли­чить эффек­тив­ность рабо­ты про­цес­со­ра, мы раз­де­ля­ем каж­дую ста­дию в так назы­ва­е­мый кон­вей­ер.

Клас­си­че­ский спо­соб понять это – по ана­ло­гии со стир­кой. У вас есть две загруз­ки, и стир­ка и суш­ка каж­дой из них зани­ма­ет час. Вы може­те поло­жить первую загруз­ку в сти­раль­ную маши­ну, а затем в сушил­ку, когда она будет гото­ва, а затем начать вто­рую загруз­ку. Это зай­мет четы­ре часа. Одна­ко, если раз­де­лить рабо­ту и начать вто­рую загруз­ку стир­ки во вре­мя пер­вой загруз­ки, то обе загруз­ки мож­но будет выпол­нить за три часа. Вре­мя сокра­ща­ет­ся на один час с коли­че­ством загру­зок, кото­рое у вас есть, и коли­че­ством сти­раль­ных машин и суши­лок. Для выпол­не­ния инди­ви­ду­аль­ной загруз­ки все рав­но тре­бу­ет­ся два часа, но подоб­ное “пере­се­че­ние” уве­ли­чи­ва­ет общую про­из­во­ди­тель­ность с 0,5 загрузок/час до 0,75 загрузок/час.

Как работает процессор вашего компьютера?

Гра­фи­че­ское изоб­ра­же­ние вычис­ли­тель­но­го кон­вей­е­ра, исполь­зу­е­мо­го в ядре Bobcat ком­па­нии AMD с 2011 года. Обра­ти­те вни­ма­ние, насколь­ко оно слож­ное и сколь­ко эта­пов при­сут­ству­ет.

ЦП исполь­зу­ют этот же метод для повы­ше­ния про­пуск­ной спо­соб­но­сти. Совре­мен­ный ARM или x86 про­цес­сор может иметь более 20 сту­пе­ней кон­вей­е­ра, что озна­ча­ет, что в любой момент вре­ме­ни ядро обра­ба­ты­ва­ет более 20 раз­лич­ных инструк­ций одно­вре­мен­но. Каж­дая архи­тек­ту­ра уни­каль­на, но в нем может быть 4 цик­ла для извле­че­ния, 6 цик­лов для деко­ди­ро­ва­ния, 3 цик­ла для выпол­не­ния и 7 цик­лов для обнов­ле­ния резуль­та­тов обрат­но в память.

Воз­вра­ща­ясь к пере­хо­дам, наде­юсь, вы нач­не­те видеть про­бле­му. Если мы не зна­ем, что инструк­ция явля­ет­ся пере­хо­дом до 10-го цик­ла, мы уже нача­ли выпол­нять 9 новых инструк­ций, кото­рые могут быть недей­стви­тель­ны, если пере­ход будет сде­лан. Что­бы обой­ти эту про­бле­му, про­цес­со­ры име­ют очень слож­ные струк­ту­ры, так назы­ва­е­мые пред­ска­за­те­ли пере­хо­дов. Они исполь­зу­ют схо­жие кон­цеп­ции из машин­но­го обу­че­ния, что­бы попы­тать­ся уга­дать, будет ли сде­лан пере­ход или нет. Хит­ро­спле­те­ния пред­ска­за­те­лей пере­хо­дов выхо­дят дале­ко за рам­ки этой ста­тьи, но на базо­вом уровне они отсле­жи­ва­ют состо­я­ние преды­ду­щих пере­хо­дов, что­бы узнать веро­ят­ность, с кото­рой будет взя­та сле­ду­ю­щая ветвь или нет. Совре­мен­ные пред­ска­за­те­ли пере­хо­дов могут иметь точ­ность 95% и выше.

Как толь­ко резуль­тат рабо­ты пере­хо­да ста­нет изве­стен навер­ня­ка, счет­чик команд будет обнов­лен, и про­цес­сор перей­дет к выпол­не­нию сле­ду­ю­щей инструк­ции. Если пере­ход был оши­боч­но спро­гно­зи­ро­ван, то про­цес­сор выбро­сит все инструк­ции после пере­хо­да, кото­рые он оши­боч­но начал выпол­нять, и запу­стит­ся сно­ва с пра­виль­но­го места.

Внеочередное исполнение

Теперь, когда мы зна­ем, как выпол­ня­ют­ся три наи­бо­лее рас­про­стра­нен­ных типа инструк­ций, давай­те рас­смот­рим неко­то­рые из более про­дви­ну­тых функ­ций про­цес­со­ра. Прак­ти­че­ски все совре­мен­ные про­цес­со­ры на самом деле не испол­ня­ют инструк­ции в том поряд­ке, в кото­ром они полу­че­ны. Пара­диг­ма, назы­ва­е­мая “неупо­ря­до­чен­ное выпол­не­ние”, исполь­зу­ет­ся для мини­ми­за­ции вре­ме­ни про­стоя в ожи­да­нии окон­ча­ния выпол­не­ния дру­гих инструк­ций.

Если про­цес­сор зна­ет, что пред­сто­я­щая инструк­ция тре­бу­ет дан­ных, кото­рые не будут гото­вы вовре­мя, он может пере­клю­чить поря­док испол­не­ния инструк­ций и взять неза­ви­си­мую инструк­цию из более позд­них вер­сий про­грам­мы, пока она ждет. Такая реор­га­ни­за­ция инструк­ций явля­ет­ся чрез­вы­чай­но мощ­ным инстру­мен­том, но это дале­ко не един­ствен­ная хит­рость, кото­рую исполь­зу­ют про­цес­со­ры.

Как работает процессор вашего компьютера?

Дру­гая функ­ция повы­ше­ния про­из­во­ди­тель­но­сти назы­ва­ет­ся пред­вы­бор­кой. Если бы вы захо­те­ли узнать вре­мя, за кото­рое выпол­нит­ся слу­чай­ная инструк­ция от нача­ла до кон­ца, вы бы обна­ру­жи­ли, что доступ к памя­ти зани­ма­ет боль­шую часть вре­ме­ни. Пред­ва­ри­тель­ная выбор­ка – это блок в цен­траль­ном про­цес­со­ре, кото­рый пыта­ет­ся загля­нуть в буду­щие инструк­ции и понять, какие дан­ные им пона­до­бят­ся. Если он уви­дит дан­ные, отсут­ству­ю­щие в кэше ЦП, то он про­тя­нет руку помо­щи опе­ра­тив­ной памя­ти и запи­шет эти дан­ные в кэш. Отсю­да и назва­ние пред­ва­ри­тель­ной выбор­ки.

Ускорители

Еще одна важ­ная функ­ция, кото­рая начи­на­ет исполь­зо­вать­ся в про­цес­со­рах, – это уско­ри­те­ли для реше­ния кон­крет­ных задач. Это схе­мы, вся рабо­та кото­рых заклю­ча­ет­ся в выпол­не­нии одной малень­кой зада­чи как мож­но быст­рее. Это может вклю­чать в себя шиф­ро­ва­ние, коди­ро­ва­ние видео или машин­ное обу­че­ние.

ЦП может выпол­нять эти зада­чи само­сто­я­тель­но, но гораз­до эффек­тив­нее, если для них выде­лен отдель­ный блок. Отлич­ным при­ме­ром это­го явля­ет­ся встро­ен­ная (инте­гри­ро­ван­ная) гра­фи­ка по срав­не­нию со спе­ци­а­ли­зи­ро­ван­ной видео­кар­той. Конеч­но, про­цес­сор может выпол­нять вычис­ле­ния, необ­хо­ди­мые для обра­бот­ки гра­фи­ки, но нали­чие выде­лен­но­го для них бло­ка обес­пе­чи­ва­ет на поря­док боль­шую про­из­во­ди­тель­ность. С ростом чис­ла таких уско­ри­те­лей фак­ти­че­ское ядро CPU может зани­мать лишь неболь­шую часть чипа.

На рисун­ке ниже пока­зан про­цес­сор Intel, создан­ный несколь­ко лет назад. Боль­шая часть про­стран­ства заня­та ядра­ми и кэшем. На вто­ром рисун­ке ниже изоб­ра­жен гораз­до более новый AMD чип. Боль­шая часть про­стран­ства заня­та дру­ги­ми ком­по­нен­та­ми, а не ядром.

Как работает процессор вашего компьютера?

Архи­тек­ту­ра пер­во­го поко­ле­ния Intel Nehalem. Обра­ти­те вни­ма­ние, что ядра и кэш зани­ма­ют боль­шую часть места.

Как работает процессор вашего компьютера?

Гра­фи­че­ская схе­ма от AMD, пока­зы­ва­ю­щая боль­шое коли­че­ство места в про­цес­со­ре, отве­ден­но­го под уско­ри­те­ли и внеш­ние интер­фей­сы.

Многоядерность

Послед­няя важ­ная функ­ция, кото­рую мы рас­смот­рим, это то, как мы можем соеди­нить несколь­ко отдель­ных про­цес­со­ров вме­сте, что­бы сфор­ми­ро­вать мно­го­ядер­ный про­цес­сор. Это не так про­сто, как сло­жить несколь­ко копий одно­ядер­но­го ЦП, о кото­ром мы гово­ри­ли ранее. Точ­но так же, как нет про­сто­го спо­со­ба пре­вра­тить одно­по­точ­ную про­грам­му в мно­го­по­точ­ную, та же самая кон­цеп­ция при­ме­ни­ма и к аппа­рат­но­му обес­пе­че­нию. Про­бле­мы воз­ни­ка­ют из-за зави­си­мо­сти меж­ду ядра­ми.

Для, ска­жем, 4‑ядерной схе­мы, про­цес­сор дол­жен быть спо­со­бен выда­вать инструк­ции в 4 раза быст­рее. Ему так­же необ­хо­ди­мы четы­ре отдель­ных интер­фей­са к памя­ти. При нали­чии несколь­ких объ­ек­тов, рабо­та­ю­щих на потен­ци­аль­но одних и тех же кусоч­ках дан­ных, долж­ны быть реше­ны такие про­бле­мы, как коге­рент­ность и согла­со­ван­ность. Если оба ядра выпол­ня­ют инструк­ции, исполь­зу­ю­щие одни и те же дан­ные, то отку­да они узна­ют, кто име­ет пра­виль­ное зна­че­ние? Что, если одно ядро моди­фи­ци­ро­ва­ло дан­ные, быст­рее дру­го­го? Посколь­ку у них есть отдель­ные кэши, кото­рые могут хра­нить пере­се­ка­ю­щи­е­ся дан­ные, необ­хо­ди­мо исполь­зо­вать слож­ные алго­рит­мы и кон­трол­ле­ры для реше­ния этих кон­флик­тов.

Пра­виль­ное пред­ска­за­ние пере­хо­дов так­же очень важ­но по мере уве­ли­че­ния коли­че­ства ядер в про­цес­со­ре. Чем боль­ше ядер выпол­ня­ют инструк­ции одно­вре­мен­но, тем выше веро­ят­ность того, что одно из них обра­ба­ты­ва­ет инструк­цию в резуль­та­те пере­хо­да. Это озна­ча­ет, что поток команд может изме­нить­ся в любое вре­мя.

Обыч­но каж­дое ядро обра­ба­ты­ва­ет поток команд из раз­ных пото­ков. Это помо­га­ет умень­шить зави­си­мость меж­ду ядра­ми. Вот поче­му, если вы про­ве­ри­те дис­пет­чер задач, то часто уви­ди­те, что одно ядро рабо­та­ет усерд­но, а дру­гие – едва ли. Мно­гие про­грам­мы не пред­на­зна­че­ны для мно­го­по­точ­ной рабо­ты. Так­же могут быть опре­де­лен­ные слу­чаи, когда более эффек­тив­но исполь­зо­вать одно ядро для выпол­не­ния рабо­ты вме­сто того, что­бы опла­чи­вать наклад­ные рас­хо­ды, свя­зан­ные с попыт­кой раз­де­лить рабо­ту.

Конструктивные особенности

Боль­шая часть этой ста­тьи была посвя­ще­на архи­тек­ту­ре ЦП, посколь­ку имен­но в ней и заклю­ча­ет­ся боль­шая часть слож­но­стей. Одна­ко все это нуж­но созда­вать в мате­ри­аль­ном мире, а это добав­ля­ет еще один уро­вень слож­но­сти.

Для син­хро­ни­за­ции всех ком­по­нен­тов про­цес­со­ра исполь­зу­ет­ся так­то­вый сиг­нал. Совре­мен­ные про­цес­со­ры обыч­но рабо­та­ют с часто­той от 3.0 ГГц до 5.0 ГГц, и, похо­же, за послед­нее деся­ти­ле­тие это не изме­ни­лось. На каж­дом из этих цик­лов мил­ли­ар­ды тран­зи­сто­ров внут­ри мик­ро­схе­мы вклю­ча­ют­ся и выклю­ча­ют­ся.

Так­то­вая часто­та име­ет реша­ю­щее зна­че­ние для обес­пе­че­ния того, что­бы по мере про­дви­же­ния каж­дой ста­дии вычис­ли­тель­но­го кон­вей­е­ра все зна­че­ния отоб­ра­жа­лись в нуж­ное вре­мя. Она же опре­де­ля­ет, сколь­ко команд может обра­ба­ты­вать про­цес­сор в секун­ду. Уве­ли­че­ние часто­ты за счет “раз­го­на” уско­рит рабо­ту чипа, но так­же и уве­ли­чит потреб­ле­ние энер­гии и теп­ло­вы­де­ле­ние.

Тем­пе­ра­ту­ра – злей­ший враг про­цес­со­ра. По мере нагре­ва­ния элек­тро­ни­ки мик­ро­ско­пи­че­ские тран­зи­сто­ры могут начать дегра­ди­ро­вать и пор­тить­ся. Это может при­ве­сти к повре­жде­нию мик­ро­схе­мы, если не отве­сти теп­ло. Вот поче­му все про­цес­со­ры постав­ля­ют­ся с рас­се­и­ва­те­ля­ми теп­ла. Фак­ти­че­ская крем­ни­е­вая мат­ри­ца ЦП может зани­мать толь­ко 20% пло­ща­ди поверх­но­сти физи­че­ско­го про­цес­со­ра. Уве­ли­чен­ная пло­щадь поверх­но­сти более рав­но­мер­но рас­пре­де­ля­ет теп­ло. Это так­же поз­во­ля­ет уве­ли­чить коли­че­ство кон­так­тов для вза­и­мо­дей­ствия с внеш­ни­ми ком­по­нен­та­ми.

Совре­мен­ные цен­траль­ные про­цес­со­ры могут иметь тыся­чу и более вход­ных и выход­ных выво­дов. Мобиль­ный чип может иметь все­го несколь­ко сотен выво­дов. Неза­ви­си­мо от кон­струк­ции, око­ло поло­ви­ны из них посвя­ще­но энер­го­снаб­же­нию, а осталь­ные исполь­зу­ют­ся для пере­да­чи дан­ных. Это вклю­ча­ет в себя обмен дан­ны­ми с опе­ра­тив­ной памя­тью, набо­ром мик­ро­схем, памя­тью, PCIe устрой­ства­ми и мно­гое дру­гое. Посколь­ку высо­ко­про­из­во­ди­тель­ные про­цес­со­ры потреб­ля­ют сот­ни и более ампер при пол­ной нагруз­ке, им нуж­ны сот­ни кон­так­тов, что­бы рав­но­мер­но рас­пре­де­лить теку­щую нагруз­ку. Обыч­но кон­так­ты позо­ло­че­ны для улуч­ше­ния элек­тро­про­вод­но­сти. Раз­лич­ные про­из­во­ди­те­ли исполь­зу­ют раз­лич­ные схе­мы рас­по­ло­же­ния кон­так­тов в сво­их мно­го­чис­лен­ных линей­ках про­дук­ции.

Складываем все вместе

Завер­шая ста­тью, мы рас­смот­рим дизайн про­цес­со­ра Intel Core 2. Это отно­сит­ся к 2006 году, так что неко­то­рые дета­ли могут быть уста­рев­ши­ми, но луч­ших подроб­но­стей о более новых схе­мах нет.

Начи­ная с само­го нача­ла, у нас есть кэш инструк­ций и ITLB. Буфер ассо­ци­а­тив­ной транс­ля­ции (TLB) исполь­зу­ет­ся для того, что­бы помочь про­цес­со­ру узнать, куда в памя­ти нуж­но зай­ти, что­бы най­ти необ­хо­ди­мую инструк­цию. Эти инструк­ции хра­нят­ся в кэше инструк­ций L1, а затем отправ­ля­ют­ся в пре-деко­дер. Архи­тек­ту­ра x86 чрез­вы­чай­но слож­на и плот­на, поэто­му есть мно­го ста­дий для деко­ди­ро­ва­ния. Тем вре­ме­нем, алго­рит­мы пред­ска­за­те­ля пере­хо­дов и пред­вы­бор­ки ищут любые потен­ци­аль­ные про­бле­мы, вызван­ные посту­па­ю­щи­ми инструк­ци­я­ми.

Как работает процессор вашего компьютера?

Отту­да инструк­ции отправ­ля­ют­ся в оче­редь инструк­ций. Вспом­ни­те, как вне­оче­ред­ное испол­не­ние поз­во­ля­ет про­цес­со­ру выпол­нять инструк­ции и делать это в наи­бо­лее под­хо­дя­щий момент. В этой оче­ре­ди хра­нят­ся теку­щие инструк­ции. Как толь­ко про­цес­сор зна­ет, какую инструк­цию луч­ше все­го выпол­нить, она далее деко­ди­ру­ет­ся в мик­ро­опе­ра­цию. В то вре­мя как инструк­ция может содер­жать “тяже­лую” зада­чу для про­цес­со­ра, мик­ро-опе­ра­ции – это гра­ну­ли­ро­ван­ные зада­чи, кото­рые лег­че интер­пре­ти­ру­ют­ся цен­траль­ным про­цес­со­ром.

Затем эти инструк­ции попа­да­ют в таб­ли­цу реги­стро­вых псев­до­ни­мов, буфер оче­ре­дей (ROB) и еди­ную стан­цию резер­ви­ро­ва­ния. Точ­ное функ­ци­о­ни­ро­ва­ние этих трех ком­по­нен­тов доволь­но слож­ное (думаю, курс аспи­ран­ту­ры в уни­вер­си­те­те), но они исполь­зу­ют­ся в алго­рит­ме вне­оче­ред­но­го испол­не­ния, что­бы помочь управ­лять зави­си­мо­стя­ми меж­ду инструк­ци­я­ми.

Одно “ядро” на самом деле будет иметь мно­го АЛУ и пор­тов памя­ти. Вхо­дя­щие опе­ра­ции поме­ща­ют­ся в стан­цию резер­ви­ро­ва­ния до тех пор, пока ALU или порт памя­ти не ста­нут доступ­ны для исполь­зо­ва­ния. Как толь­ко необ­хо­ди­мый ком­по­нент будет досту­пен, инструк­ция будет обра­бо­та­на с помо­щью кэша дан­ных L1. Выво­ди­мые резуль­та­ты будут сохра­не­ны, и про­цес­сор теперь готов к запус­ку на сле­ду­ю­щей коман­де.

Хотя эта ста­тья не была заду­ма­на как окон­ча­тель­ное руко­вод­ство к тому, как имен­но рабо­та­ет каж­дый про­цес­сор, она долж­на дать вам хоро­шее пред­став­ле­ние об их внут­рен­ней рабо­те и слож­но­стях. Чест­но гово­ря, никто кро­ме AMD и Intel на самом деле не зна­ет, как рабо­та­ют их про­цес­со­ры. Каж­дый раз­дел этой ста­тьи пред­став­ля­ет собой целую область иссле­до­ва­ний и раз­ра­бо­ток, поэто­му инфор­ма­ция, пред­став­лен­ная здесь, лишь зада­ет направ­ле­ние.

источ­ник: techspot.com