В последнее время я написал несколько статей по многоядерной технологии; одна из них была о многоядерных CPU и одна о многоядерном программировании. Глядя на то, как много многоядерных мыслей вертится у меня в голове, я подумал, что напишу еще одну статью по данной теме. Эта статья рассмотрит согласование кэша, поскольку это относится к многоядерным процессорам.
Что такое согласование кэша? В контексте многоядерных процессоров согласование кэша относится к целостности данных, хранящихся в кэше каждого ядра. Но почему согласование кэша так важно? Для ответа на этот вопрос я обращусь к многоядерным процессорам, показанным на рисунке 1. Предположим, что имеется две нити, выполняющиеся на процессоре; одна в ядре 1 и одна в ядре 2. Теперь представим, что каждое ядро получает из основной памяти переменную ‘x’ и помещает эту переменную в свой кэш. Теперь, если ядро 1 изменит значение переменной ‘x’, то значение, которое хранится в кэше ядра 2 для переменной ‘x’ рассинхронизовано со значениемя в кэше ядра 1. Это важная проблема многоядерных процессоров. Фактически, эта проблема не очень отличается от проблемы многопроцессорного (на многих микросхемах) согласования кэша.
Рисунок 1: Схема многоядерного процессора (любезно предоставлена csail.mit.edu)
В многоядерных процессорах проблема согласования кэша решена использованием внутриядерной шины. Внутриядерная шина — это шина, которая соединена с кэшем каждого ядра; смотрите на рисунке 2.
Рисунок 2: Многоядерная микросхема с внутриядерной шиной (любезно предоставлена csail.mit.edu)
Существует два основных метода использования внутриядерной шины для извещения других ядер, когда ядро меняет что-либо в своем кэше. Один метод упоминается как ‘обновление’. В методе обновления если ядро 1 изменяет переменную ‘x’, оно отправляет обновленное значение ‘x’ по внутриядерной шине. Каждый кэш постоянно слушает внутриядерную шину; если кэш видит на шине переменную, копия которой у него есть, он прочитает обновленное значение. Это позволяет удостовериться, что все кэши содержат наиболее свежее значение переменной
Другой метод, который использует внутриядерную шину называется аннулирование. Этот метод посылает сообщение аннулирования по внутриядерной шине при изменении переменной. Другие кэши прочитают этот сигнал аннулирования, и если их ядро попытается получить доступ к этой переменной, результатом будет отсутствие ее в кэше и переменная будет прочитана из основной памяти.
На первый взгляд может показаться, что метод обновления более предпочтителен, поскольку нам известно, что отсутствие в кэше может вызвать значительные затраты производительности. Однако, метод обновления вызывает значительное количество трафика на внутриядерной шине, поскольку сигнал обновления должен посылаться по шине при каждом обновлении переменной. Метод аннулирования требует лишь посылки сигнала аннулирования при первом изменении переменной; вот почему метод аннулирования более предпочтительный.
Этот пример метода аннулирования — очень элементарный. Большая работа была выполнена за эти годы для улучшения производительности согласования кэша. Это привело ко многим протоколам согласования кэша.
MSI — это основной, хорошо известный протокол согласования кэша. MSI означает Modified, Shared, and Invalid (измененный, общий, недействительный). Имеется три состояния, в которых может находиться линия кэша. Измененное состояние означает, что переменная в кэше была изменена и, таким образом, имеет отличное значение от того, которое находится в основной памяти; кэш отвечает за запись переменной назад в память. Общее состояние означает, что переменная имеется по меньшей мере в одном кэше и не изменена; кэш может удалить переменную без записи ее обратно в основную память. Недействительное состояние означает, что значение переменной было изменено другим кэшем и эта переменная недействительна; кэш должен прочитать новое значение из основной памяти (или из другого кэша).
Другой хорошо известный протокол согласования кэша — это протокол MESI. MESI означает Modified, Exclusive, Shared, and Invalid (измененный, единственный, общий, недействительный). Состояния измененный и недействительный для этого протокола точно такие же как и для протокола MSI. Этот протокол представляет новое состояние — единственное. Единственное состояние означает, что переменная имеется только в этом кэше, и ее значение совпадает со значением в основной памяти. Теперь это означает, что общее состояние показывает, что переменная содержится в более чем одном кэше.
Протокол MOSI идентичен протоколу MSI за исключением того, что он добавляет состояние Owned (принадлежащий). Состояние принадлежащий означает, что процессор «владеет» переменной и будет предоставлять текущее значение другим кэшам, когда они запросят (или как минимум он решит, что предоставит его при запросе). Это полезно, потому что другому кэшу не нужно будет читать значение из основной памяти и получит его от «Владеющего» кэша на много, на много быстрее.
MOESI
Протокол MOESI — это комбинация протоколов MESI и MOSI.
Описанные выше протоколы работают очень хорошо и в большинстве случаев замечены и в многоядерных и в многопроцессорных системах. В примере многоядерного процессора, показанного мною выше, эти протоколы будут работать хорошо. В будущем, когда процессоры будут содержать множество ядер, я уверен, что эти типы протоколов будут генерировать значительный трафик по внутриядерной шине. Один из методов преодоления этого будет состоять в использовании подхода на основе каталога. В подходе на основе каталога каждый кэш может связывать состояние его переменных с единственным каталогом вместо трансляции состояния всем ядрам.
На рисунках 1 и 2 ядра процессора соединены посредством шины, это не тот случай, когда количество ядер начинает стремительно увеиличаться. Я надеюсь, что я показал вам, что процессор сам по себе — это настоящая сеть из ядер, которая вполне похожа на на компьютерную сеть с различными топологиями связи. С учетом этого многие процессоры будут разрабатываться так, что их ядра будут соединены в топологию кольцо. Конечно, если мы рассматриваем процессор как сеть ядер, есть несколько других проблем кроме топологии, которые необходимо рассмотреть. Например, протоколы уровня приложений, сессий, и, по существу, все вопросы, которые я рассматривал в моей серии статей модель OSI, будут применены к обсужденным сетям из ядер.
Другой фактор, усложняющий проблему согласования кэша, состоит в том, что некоторые системы содержат множество процессоров, в каждом из которых множество ядер. В этом случае каждый процессор должен поддерживать свой кэш согласованным со всеми другими, также как и согласованным с кэшами других процессоров. Это требует наличия стратегии согласования кэша каждого процессора и стратегии более высокого уровня для поддержания кэшей согласованными на уровне системы. Имейте в виду, что стратегии для каждого процессора не должны (и не будут должны) совпадать со стратегией, используемой для соседнего процессора. Эти стратегии вытекают из возможностей и требований каждого индивидуального процессора. Например, даже сегодня у многих компьютеров есть отдельный графический процессор, который может иметь различное количество ядер, используемых различными способами. Вероятно это может привести к стратегии согласования кэша, отличной от стратегии, оптимизированной для CPU.
www.windowsnetworking.com