
Широковещательная запись
При широковещательной записи каждый запрос на запись в конкретную кэш-память направляется также и всем остальным кэшам системы. Это заставляет контроллеры кэшей проверить, нет ли там копии изменяемого блока. Если такая копия найдена, то она аннулируется или обновляется, в зависимости от приме-няемой схемы. Метод широковещательной записи связан с дополнительными групповыми операциями с памятью (транзакциями), поэтому он реализован лишь в больших вычислительных системах.
Протоколы наблюдения
В протоколах наблюдения (snoopy protocols или просто snooping) ответст-венность за поддержание когерентности всех кэшей многопроцессорной системы возлагается на контроллеры кэшей. В системах, где реализованы протоколы наблюдения, контроллер каждой локальной кэш-памяти содержит блок слежения за шиной (рис. 3.3), который следит за всеми транзакциями на общей шине и контролирует все операции записи. Процессоры должны широковещательно передавать на шину любые запросы на доступ к памяти, потенциально способные изменить состояние когерентности совместно используемых блоков данных. Затем локальный контроллер кэш-памяти каждого процессора определяет, при-сутствует ли в его кэш-памяти копия модифицируемого блока, и если это так, то такой блок аннулируется или обновляется.
Протоколы наблюдения характерны для мультипроцессорных систем на базе шины, поскольку общая шина достаточно просто обеспечивает как наблю-
Рис. 3.3. Кэш-память с контроллером наблюдения за шиной
дение, так и широковещательную передачу сообщений. Однако здесь необходимо принимать меры, чтобы повышенная нагрузка на шину, связанная с наблюдением и трансляцией сообщений, не «съела» преимуществ локальных кэшей.
В большинстве протоколов стратегия обеспечения когерентности кэш-памяти расценивается как смена состояний в конечном автомате. При таком подходе предполагается, что любой блок в локальной кэш-памяти может нахо-диться в одном из фиксированных состояний. Обычно число таких состояний не превышает четырех, поэтому для каждой строки кэш-памяти в ее теге имеются два бита, называемые битами состояния (SB, Status Bit). Следует также учиты-вать, что некоторым идентичным по смыслу состояниям строки кэша разработ-чиками различных протоколов присвоены разные наименования. Например, сос-тояние строки, в которой были произведены локальные изменения, в одних протоколах называют Dirty («грязный»), а в других – Modified («модифициро-ванный» или «измененный»).
Протокол сквозной записи.
Этот протокол представляет собой расширение стандартной процедуры сквозной записи, известной по однопроцессорным системам. В нем запись в локальную кэш-память любого процессора сопровождается записью в основную память. В дополнение, все остальные кэши, содержащие копию измененного блока, должны объявить свою копию недействительной. Протокол считается наиболее простым, но при большом числе процессоров приводит к значительному трафику шины, поскольку требует повторной перезагрузки измененного блока в те кэши, где этот блок ранее был объявлен недействительным. Кроме того, производительность процессоров при записи в совместно используемые пере- менные может упасть из-за того, что для продолжения вычислений процессоры должны ожидать, пока завершатся все операции записи.
Протокол обратной записи.
В основе протокола лежит стандартная схема обратной записи, за исключением того, что расширено условие перезаписи блока в основную память. Так, если копия блока данных в одном из локальных кэшей подверглась модификации, этот блок будет переписан в основную память при выполнении одного из двух условий:
блок удаляется из той кэш-памяти, где он был изменен;
другой процессор обратился к своей копии измененного блока.
Если содержимое строки в локальном кэше не модифицировалось, пере-запись в основную память не производится. Доказано, что такой протокол по эффективности превосходит схему сквозной записи, поскольку необходимо пере-писывать только измененные блоки.
Несмотря на более высокую производительность, протокол обратной записи также не идеален, так как решает проблему когерентности лишь частично. Когда процессор обновляет информацию в своей кэш-памяти, внесенные изменения не наблюдаемы со стороны других процессоров до момента перезаписи измененного блока в основную память. То есть другие процессоры не знают, что содержимое по данному адресу было изменено до тех пор, пока соответствующая строка не будет переписана в основную память. Эта проблема часто решается путем наложения условия, что кэши, которые собираются изменить содержимое совме-стно используемого блока, должны получить эксклюзивные права на этот блок.
Протокол однократной записи.
Протокол однократной записи (write-once), предложенный Гудменом, – пер-вый из протоколов обеспечения когерентности кэш-памяти. Он относится к схемам на основе наблюдения, действующим на принципе записи с аннулиро-ванием. Протокол предполагает, что первая запись в любую строку кэш-памяти производится по схеме сквозной записи, при этом контроллеры других кэшей объявляют свои копии измененного блока недействительными. С этого момента
Рис. 3.4. Протокол однократной записи.
только процессор, произведший запись, обладает достоверной копией данных. Последующие операции записи в рассматриваемую строку выполняются в соот-ветствии с протоколом обратной записи.
Основной недостаток протокола состоит в том, что он требует первона-чальной записи в основную память, даже если эта строка не используется дру-гими процессорами. Диаграмма состояний протокола показана на рис. 3.4.
Для реализации протокола однократной записи каждой строке кэш-памяти приданы два бита. Это позволяет представить четыре состояния, в которых может находиться строка: «недействительная» (I, Invalid), «достоверная» (V, Valid), «резервированная» (R, Reserved) и «измененная» (D, Dirty). В состоянии I строка кэш-памяти не содержит достоверных данных. В состоянии V строка кэша содержит данные, считанные из основной памяти и к данному моменту еще не измененные, то есть строка кэша и блок основной памяти согласованы. Состояние R означает, что с момента считывания из основной памяти в блоке локальной кэш-памяти было произведено только одно изменение, причем оно учтено и в основной памяти. В состоянии R содержимое строки кэша и основной памяти также является согласованным. Наконец, статус D показывает, что строка кэш-памяти модифицировалась более чем один раз и последние изменения еще не переписаны в основную память. В этом случае строка кэша и содержимое основ-ной памяти не согласованы.
В процессе выполнения программ блоки слежения за шиной каждой кэш-памяти проверяют, не совпадает ли адрес ячейки, изменяемой в какой-либо ло-кальной кэш-памяти, с одним из адресов в собственном кэше. Если такое совпа-дение произошло при выполнении операции записи, контроллер кэша изменяет статус соответствующей строки в своей кэш-памяти на I. Если совпадение обна-ружено при выполнении операции чтения, состояние строки не изменяется, за исключением случая, когда строка, проверяемая на совпадение, помечена как R или D. Если строка имеет состояние R, оно изменяется на V. Когда строка кэша отмечена как измененная (D), локальная система запрещает считывание элемента данных из основной памяти и данные берутся непосредственно из локальной кэш-памяти, как из источника наиболее «свежей» информации. Во время того же доступа к шине или непосредственно после него обновленное значение должно быть переписано в основную память, а состояние строки скорректировано на V.
В протоколе однократной записи когерентность сохраняется благодаря тому, что когда выполняется запись, копии изменяемой строки во всех остальных локальных кэшах объявляются недействительными. Таким образом, кэш, выпол-няющий операцию записи, становится обладателем единственной достоверной копии (при первой записи в строку такая же копия будет и в основной памяти). При первой записи строка переводится в состояние R, и если впоследствии такая строка удаляется из кэш-памяти, ее перезапись в основную память не требуется. При последующих изменениях строки она помечается как D и работает протокол обратной записи.
Протокол Synapse.
Данный протокол, реализованный в отказоустойчивой мультипроцессорной системе Synapse N + 1, представляет собой версию протокола однократной за-писи, где вместо статуса R используется статус D. Кроме того, переход из со-стояния D в состояние V при промахе, возникшем в ходе чтения данных другим процессором, заменен достаточно громоздкой последовательностью. Связано это с тем, что при первом кэш-промахе чтения запросивший процессор не может получить достоверную копию непосредственно из той локальной кэш-памяти, где произошло изменение данных, и вынужден обратиться напрямую к основной памяти.
Протокол Berkeley.
Протокол Berkeley был применен в мультипроцессорной системе Berkeley, построенной на базе RISC-процессоров. Снижение издержек, возникающих в результате кэш-промахов, обеспечивается благодаря реализованной в этом про-токоле идее прав владения на строку кэша. Обычно владельцем прав на все блоки данных считается основная память. Прежде чем модифицировать содержимое строки в своей кэш-памяти, процессор должен получить права владения на данную строку. Эти права приобретаются с помощью специальных операций чтения и записи. Если при доступе к блоку, собственником которого в данный момент не является основная память, происходит кэш-промах, процессор, явля-ющийся владельцем строки, предотвращает чтение из основной памяти и сам снабжает запросивший процессор данными из своей локальной кэш-памяти.
Другим улучшением является введение состояния совместного использо-вания (shared). Когда процессор производит запись в одну из строк своей ло-кальной кэш-памяти, он обычно формирует сигнал аннулирования копий изме-няемого блока в других кэшах. В протоколе Berkeley сигнал аннулирования формируется только при условии, что в прочих кэшах имеются такие копии. Это позволяет существенно снизить непроизводительный трафик шины. Возможны следующие сценарии.
Прежде всего, каждый раз, когда какой-либо процессор производит запись в свою кэш-память, изменяемая строка переводится в состояние «измененная, частная» (PD, Private Dirty). Далее, если строка является совместно используемой, на шину посылается сигнал аннулирования, и во всех локальных кэшах, где есть копия данного блока данных, эти копии переводятся в состояние «недействи-тельная» (I, Invalid). Если при записи имел место промах, процессор получает копию блока из кэша текущего хозяина запрошенного блока. Лишь после этих действий процессор производит запись в свой кэш.
При кэш-промахе чтения процессор посылает запрос владельцу блока, чтобы получить наиболее свежую версию последнего, и переводит свою новую копию в состояние «только для чтения» (RO, Read Only). Если владельцем строки был другой процессор, он помечает свою копию блока как «разделяемую из-мененную» (SD, Shared Dirty). Диаграмма протокола Berkeley показана на рис. 3.5.
Сравнивая протоколы однократной записи и Berkeley, можно отметить следующее. Оба протокола используют стратегию обратной записи, при которой измененные блоки удерживаются в кэш-памяти как можно дольше. Основная память обновляется только при удалении строки из кэша. Верхняя граница общего количества транзакций записи на шине определяется той частью про-токола однократной записи, где реализуется сквозная запись, так как последняя стратегия порождает на шине операцию записи при каждом изменении, иниции- рованном процессором. Поскольку первая операция записи в протоколе одно-
Рис. 3.5. Протокол Berkeley.
кратной записи является сквозной, она производится даже если данные не яв-ляются совместно используемыми. Это влечет дополнительный трафик шины, который возрастает с увеличением емкости кэш-памяти.
Для постоянно читаемой и обновляемой строки в протоколе однократной записи необходимы считывание этой строки в кэш, ее локальная модификация в кэше и обратная запись в память. Вся процедура требует двух операций на шине: чтения из основной памяти (ОП) и обратной записи в ОП. С другой стороны, протокол Berkeley исходит из получения прав на строку. Далее блок модифицируется в кэше. Если до удаления из кэша к строке не производилось обращение, число циклов шины будет таким же, как и в протоколе однократной записи. Однако более вероятно, что строка будет запрошена опять, тогда с позиций одиночной кэш-памяти обновление строки кэша нуждается только в одной операции чтения на шине. Таким образом, протокол Berkeley пересылает строки непосредственно между кэшами, в то время как протокол однократной записи передает блок из исходного кэша в основную память, а затем из ОП в запросившие кэши, что имеет следствием общую задержку системы памяти.
Протокол Illinois.
Протокол Illinois, предложенный Марком Папамаркосом, также направлен на снижение трафика шины и времени ожидания процессором доступа к шине. В протоколе Illinois правом владения обладает любой кэш, где есть достоверная копия блока данных. В этом случае у одного и того же блока может быть несколько владельцев. Когда такое происходит, каждому процессору назначается определенный приоритет и источником информации становится владелец с более высоким приоритетом. Сигнал аннулирования формируется лишь в том случае, когда копии данного блока имеются и в других кэшах. Возможные сценарии для протокола Illinois представлены на рис. 3.6.
Рис. 3.6. Протокол Illinois
Каждый раз, когда какой-либо процессор производит запись в свою кэш-память, изменяемая строка переводится в состояние «измененная частная» (PD, Private Dirty). Если блок данных является совместно используемым, на шину посылается сигнал аннулирования и во всех локальных кэшах, где есть копия данного блока, эти копии переводятся в состояние «недействительная» (I, Invalid). Если при записи случился промах, процессор получает копию из кэша текущего владельца запрошенного блока и производит запись в свой кэш.
При кэш-промахе чтения процессор посылает запрос владельцу блока, чтобы получить наиболее свежую версию последнего, и переводит свою новую копию в состояние «эксклюзивная» (E, Exclusive) при условии, что он является единственным владельцем строки. В противном случае статус меняется на «разделяемая» (S, Shared).
Протокол Firefly.
Протокол предложен Такером и реализован в мультипроцессорной системе Firefly Multiprocessor Workstation, разработанной в исследовательском центре Digital Equipment Corporation.
В протоколе Firefly используется запись с обновлением. Возможные сос-тояния строки кэша совпадают с состояниями протокола Illinois (рис. 3.7). Отли-чие состоит в том, что стратегия обратной записи применяется только к стро- кам, находящимся в состоянии PD или E, в то время как применительно к стро-кам в состоянии S действует сквозная запись. Наблюдающие кэши при обнов-лении своих копий используют процедуру сквозной записи. Кроме того, на-блюдающие кэши, обнаружившие у себя копию строки, возбуждают специальную «разделяемую» линию шины для того, чтобы записывающий контроллер мог принять решение о том, в какое состояние переводить строку, в которую была произведена запись. «Разделяемая» линия при кэш-промахе чтения служит для информирования контроллера локальной кэш-памяти о месте, откуда поступила копия строки: из основной памяти или другого кэша. Таким образом, состояние S применяется только к тем данным, которые действительно используются совместно.
Рис. 3.7. Протокол Firefly.
Протокол имеет преимущество в том, что стратегия сквозной записи при-влекается лишь по логической необходимости. Когда ячейка перестает быть совместно используемой, то нужна только одна дополнительная операция записи, которая производится последней кэш-памятью, содержащей эту ячейку. Это приводит к тому, что протокол Firefly существенно экономнее по трафику шины по сравнению с прочими протоколами. С другой стороны, стратегия сквозной записи остается в силе до тех пор, пока строка кэша будет совместно исполь-зуемой, даже если фактически чтение строки и запись в нее производит только один процессор. Это приводит к возрастанию трафика шины, что делает неперс-пективным использование данного протокола в будущих разработках для обеспе-чения когерентности кэш-памяти.
Протокол Dragon.
Протокол применен в мультипроцессорной системе Xerox Dragon и пред-ставляет собой независимую версию протокола Firefly. В протоколе реализована процедура записи с обновлением. Строка кэша может иметь одно из пяти сос-тояний:
Invalid (I) – копия, хранящаяся в кэше, недействительна;
Read Private (RP) – существует лишь одна копия блока, и она совпадает с содержимым основной памяти;
Private Dirty (PD) – существует лишь одна копия блока, и она не совпадает с содержимым основной памяти;
Shared Clean (SC) – имеется несколько копий блока, и все они идентичны содержимому основной памяти;
Shared Dirty (SD) – имеется несколько копий блока, не совпадающих с содержимым основной памяти.
Дополнительное состояние SD предназначено для предотвращения записи в основную память. Диаграмма состояний для данного протокола приведена на рис. 3.8.
Рис. 3.8. Протокол Dragon.
Протокол MESI.
Протокол MESI (Modified/Exclusive/Shared/Invalid) широко распространен в коммерческих микропроцессорных системах на базе микропроцессоров Pentium и PowerPC. Протокол был разработан для кэш-памяти с обратной записью. Одной из основных задач протокола MESI является откладывание на максимально возможный срок операции обратной записи кэшированных данных в основную память ВС. Это позволяет улучшить производительность системы за счет мини-мизации ненужных пересылок информации между кэшами и основной памятью.
Протокол MESI приписывает каждой кэш-строке одно из четырех состоя-ний, которые контролируются двумя битами состояния MESI в теге данной стро-ки. Статус кэш-строки может быть изменен как процессором, для которого эта кэш-память является локальной, так и другими процессорами мультипроцессор-ной системы.
Согласно протоколу MESI, каждая строка бывает в одном из четырех возможных состояний:
Модифицированная (M, Modified) – данные в кэш-строке, помеченной как M, были модифицированы, но измененная информация пока не переписана в основную память. Это означает, что информация, содержащаяся в рас-сматриваемой строке, достоверна только в данном кэше, а в основной па-мяти и остальных кэшах – недостоверна.
Эксклюзивная (E, Exclusive) – данная строка в кэше не подвергалась из-менению посредством запроса на запись, совпадает с аналогичной строкой в основной памяти, но отсутствует в любом другом локальном кэше. Иными словами, она достоверна в этом кэше и недостоверна в любом другом.
Разделяемая (S, Shared) – строка в кэше совпадает с аналогичной строкой в основной памяти (данные достоверны) и может присутствовать в одном или нескольких из прочих кэшей.
Недействительная (I, Invalid) – кэш-строка, помеченная как недействитель-ная, не содержит достоверных данных и становится логически недоступной.
Порядок перехода строки кэш-памяти из одного состояния в другое зависит от:
текущего статуса строки;
выполняемой операции (чтение или запись);
результата обращения в кэш (попадание или промах);
того, является ли строка совместно используемой или нет.
На рис. 3.9 приведена диаграмма основных переходов без учета режима однократной записи.
Рис. 3.9. Протокол MESI – диаграмма состояний без учета однократной записи.
Предположим, что один из процессоров делает запрос на чтение из строки, которой в текущий момент нет в его локальной кэш-памяти (промах при чтении). Запрос будет широковещательно передан по шине. Если ни в одном из кэшей не нашлось копии нужной строки, то ответной реакции от контроллеров наблюдения других процессоров не последует, строка будет считана в кэш запросившего процессора из основной памяти, а копии будет присвоен статус E. Если в каком-либо из локальных кэшей имеется искомая копия, от соответствующего контрол-лера слежения поступит отклик, означающий доступ к совместно используемой строке. Все копии рассматриваемой строки во всех кэшах будут переведены в состояние S вне зависимости от того, в каком состоянии они были до этого.
Когда процессор делает запрос на запись в строку, отсутствующую в его локальной кэш-памяти (промах при записи), перед загрузкой в кэш-память строка должна быть считана из основной памяти (ОП) и модифицирована. Прежде чем процессор сможет загрузить строку, он должен убедиться, что в основной памяти действительно находится достоверная версия данных, то есть что в других кэшах отсутствует модифицированная копия данной строки. Формируемая в этом случае последовательность операций называется чтение с намерением модификации (RWITM, Read With Intent To Modify). Если в одном из кэшей обнаружилась копия нужной строки, причем в состоянии M, то процессор, обладающий этой копией, прерывает RWITM-последовательность и переписывает строку в ОП,
Рис. 3.10. Последовательность смены состояний в протоколе MESI: а – процессор 1 читает x; б – процессор 2 читает x; в – процессор 1 производит первую запись в x; г – процессор 1 производит очередную запись в x.
после чего меняет состояние строки в своем кэше на I. Затем RWITM-последо- вательность возобновляется и делается повторное обращение к основной памяти для считывания обновленной строки. Окончательным состоянием строки будет M, при котором ни в ОП, ни в других кэшах нет еще одной достоверной ее копии. Если копия строки существовала в другом кэше и не имела состояния M, то такая копия аннулируется и доступ к основной памяти производится немедленно.
Рис. 3.11. Переход из состояния E в состояние S в протоколе MESI: а – процессор 2 читает x; б – процессор 1 производит обратную запись x в основную память; в – процессор 2 читает x из основной памяти.
Кэш-попадание при чтении не изменяет статуса читаемой строки. Если процессор выполняет доступ для записи в существующую строку, находящуюся в состоянии S, он передает на шину широковещательный запрос для информиро-вания других кэшей, обновляет строку в своем кэше и присваивает ей статус M. Все остальные копии строки переводятся в состояние I. Если процессор произ-водит доступ по записи в строку, находящуюся в состоянии E, то он осуществляет запись в строку и изменяет ее состояние на M, поскольку другие копии строки в системе отсутствуют.
На рис. 3.10 показана типичная последовательность событий в системе из двух процессоров, запрашивающих доступ к ячейке x. Обращение к любой ячейке строки кэш-памяти рассматривается как доступ ко всей строке.
На рис. 3.11 проиллюстрированы этапы чтения процессором 2 содержимого ячейки x. Сперва наблюдается кэш-промах по чтению и процессор пытается об-ратиться к основной памяти. Процессор 1 следит за шиной, обнаруживает обра-щение к ячейке, копия которой есть в его кэш-памяти и находится в состоянии M, поэтому он блокирует операцию чтения от процессора 2. Затем процессор 1 пере-писывает строку, содержащую x, в ОП и освобождает процессор 2, чтобы тот мог повторить доступ к основной памяти. Теперь процессор 2 получает строку, со-держащую x, и загружает ее в свою кэш-память. Обе копии помечаются как S.
С учетом однократной записи диаграмма состояний, изображенная на рис. 3.9, немного видоизменяется. Все кэш-промахи при чтении вызывают переход в состояние S. Первое попадание при записи сопровождается переходом в состояние E (переход однократной записи). Следующее попадание при записи влечет за собой изменение статуса строки на M.