Какой смысл когерентности кэш-памяти?

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

12
задан Drew Noakes 18 July 2010 в 21:16
поделиться

5 ответов

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

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

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

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

7
ответ дан 2 December 2019 в 05:39
поделиться

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

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

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

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

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

10
ответ дан 2 December 2019 в 05:39
поделиться

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

1
ответ дан 2 December 2019 в 05:39
поделиться

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

1
ответ дан 2 December 2019 в 05:39
поделиться

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

Прежде всего, учтите, что ЦП обрабатывает не побайтную память, а строки кэша. Строка может иметь 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, компании, которая создает отладчик параллелизма, который вы, возможно, захотите проверить. Это помогает разобраться в деталях, когда предположения о параллелизме, согласованности и согласованности оказываются необоснованными :)

8
ответ дан 2 December 2019 в 05:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: