Какой смысл в кеш-когерентности? - PullRequest
12 голосов
/ 14 июля 2010

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

Ответы [ 6 ]

10 голосов
/ 14 июля 2010

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

Если кеши не являются связными, то «явные шаги» должны были бы обеспечить согласованность - явные шаги обычно бывают такими, как критические секции / мьютексы (например, volatile в C / C ++ достаточно редко). Для таких сервисов, как мьютексы, довольно сложно, если не невозможно, отслеживать только память, которая имеет изменения и должна быть обновлена ​​во всех кэшах, - вероятно, ей придется обновить всю память, а это если бы она могла даже отслеживать какие ядра имеют какие части этой памяти в своих кешах.

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

И представьте себе процесс, работающий на ядре 1 и прерванный. Когда он снова запланирован, он будет назначен на ядре 2.

Это было бы довольно фатально, если бы кэши не были выбраны, так как в противном случае могли бы быть остатки данных процесса в кэше ядра 1, которого нет в кэше ядра 2. Хотя для систем, работающих таким образом, ОС должна обеспечивать согласованность кэша при планировании потоков - что, вероятно, будет операцией «обновить всю память в кэшах между всеми ядрами», или, возможно, она может отслеживать грязные страницы с помощью с помощью MMU и синхронизировать только те страницы памяти, которые были изменены - опять же, аппаратное обеспечение, скорее всего, сохранит целостность кэшей более тонко и эффективно.

8 голосов
/ 19 июля 2010

Есть некоторые нюансы, которые не были учтены великими отзывами других авторов.

Прежде всего, учтите, что ЦП работает не с побайтовой памятью, а со строками кеша. Строка может иметь 64 байта. Теперь, если я выделю 2-байтовый фрагмент памяти в местоположении P, а другой ЦП выделит 8-байтовый фрагмент памяти в местоположении P + 8, а P и P + 8 будут жить в одной и той же строке кэша, заметьте, что без согласованности кэша два процессора не могут одновременно обновлять P и P + 8, не перекрывая друг друга изменениями! Поскольку каждый ЦП выполняет чтение-изменение-запись в строке кэша, они оба могут выписать копию строки, которая не включает изменения других ЦП! Последний писатель победит, и одна из ваших модификаций в памяти «исчезнет»!

Другая вещь, которую нужно иметь в виду, - это различие между связностью и последовательностью. Поскольку даже производные от x86 процессоры используют буферы хранилища, нет гарантий, что уже завершенные инструкции изменили память таким образом, что другие процессоры смогут увидеть эти изменения, даже если компилятор решил записать значение обратно в память (может быть из-за volatile?). Вместо этого моды могут сидеть в буферах магазина. Практически все центральные процессоры общего назначения согласованы с кэшем, но очень немногие процессоры имеют такую ​​же модель согласованности, как и x86. Проверьте, например, http://www.cs.nmsu.edu/~pfeiffer/classes/573/notes/consistency.html для получения дополнительной информации по этой теме.

Надеюсь, это поможет, и, кстати, я работаю в Corensic, компании, которая разрабатывает отладчик параллелизма, который вы, возможно, захотите проверить. Это помогает разобраться, когда предположения о параллелизме, согласованности и согласованности оказываются необоснованными:)

7 голосов
/ 14 июля 2010

Представьте, что вы делаете это:

lock(); //some synchronization primitive e.g. a semaphore/mutex
globalint = somevalue;
unlock();

Если бы не было когерентности кэша, этот последний unlock() должен был бы гарантировать, что globalint теперь виден везде, с когерентностью кэша все, что вам нужно сделатьэто записать его в память и позволить аппаратным средствам творить чудеса.Программное решение будет следить за тем, какая память существует, в каких кэшах, на каких ядрах, и каким-то образом обеспечивать их атомную синхронизацию.

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

1 голос
/ 15 июля 2010

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

1 голос
/ 14 июля 2010

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

0 голосов
/ 20 ноября 2014

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

Это также обеспечивает работу устаревшего многопоточного кода, как и в новыхмодели процессоров / многопроцессорные системы без внесения каких-либо изменений в код для обеспечения согласованности данных.

...