Потоки на одном ядре обращаются к одной и той же строке кэша

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

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

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


person Tyler    schedule 19.04.2017    source источник
comment
Подсказка: Напишите пинг-понговый тест, который перебрасывает данные туда-сюда между двумя потоками. Затем закрепите два потока на одном ядре (через гиперпоточность) и наблюдайте за таймингами.   -  person Mysticial    schedule 19.04.2017
comment
Спасибо за предложение. Сначала я пытался понять ожидания, но просто запустить тест, вероятно, хороший вариант. Это поможет мне на фронте задержки производительности... Я думаю, я мог бы также провести тест на условия гонки, записать увеличивающееся число в строку общего кэша и посмотреть, не совпадают ли данные когда-либо с тем, что было записано. Хотя я не уверен, докажет ли это, что это невозможно или что этого просто не произошло.   -  person Tyler    schedule 19.04.2017
comment
Связанный: заголовок stackoverflow.com/questions/32979067/ (на самом деле дубликат, если этот вопрос касается Intel с HT. Вы говорите, что у вас 128-байтный кеш строк, так что, возможно, нет. Какую микроархитектуру SMT вы используете?)   -  person Peter Cordes    schedule 29.08.2017
comment
См. также: stackoverflow.com/questions/45602699/ для теста, подобного предложенному @Mysticial. Чтение/запись одних и тех же строк может привести к большому количеству очисток конвейера неправильного выбора памяти на оборудовании Intel. Буфер хранилища разделен между двумя гиперпотоками, поэтому ложное совместное использование строки кэша по-прежнему является серьезной проблемой.   -  person Peter Cordes    schedule 29.08.2017
comment
@PeterCordes: Большое спасибо за ваш вклад выше и ниже. Эти ссылки были очень полезны. После публикации этого вопроса я узнал больше о влиянии очередей хранения/загрузки и из того, что я прочитал в https://stackoverflow.com/questions/45602699/what-are-the-latency-and-пропускнаяспособность-затраты-производителя-потребителя-обмена-заметки и ваши комментарии теперь для меня очевидны, что мой вопрос здесь на самом деле пытался спросить об очередях хранения и загрузки и о том, как на них может повлиять гиперпотоки, разделяющие строки кэша.   -  person Tyler    schedule 24.10.2017
comment
@PeterCordes: я работаю с чипом IBM POWER8, поэтому Power ISA. В этом случае я специально смотрю на режим SMT2, поэтому два потока. В руководстве по процессору объясняется, что очередь хранилища динамически распределяется между потоками, и когда загрузки попадают в хранилища в очереди, они являются кандидатами на переадресацию хранилища. При этом я знаю, что в режиме SMT2 у каждого потока есть свой LSU. Однако для меня не очевидно, имеет ли каждый LSU свою собственную очередь хранения и, если да, разрешена ли переадресация хранилища между LSU.   -  person Tyler    schedule 24.10.2017
comment
Почти наверняка не для магазинов, которые все еще спекулятивны. Возможно для магазинов, которые ушли в отставку (и поэтому готовы перейти на L1D, но еще не сделали этого). Я думаю, что порядок памяти Power достаточно слаб, поэтому было бы нормально позволить братьям и сестрам SMT видеть ваши хранилища до того, как они станут видимыми для потоков на других ядрах, я думаю (путем фиксации L1D). (В отличие от x86, где все ядра должны согласовывать общий порядок хранения, поэтому переадресация по сторонним каналам не будет разрешена, если только она не была сделана спекулятивно с откатом, если другому ядру нужна строка до того, как переадресованное хранилище зафиксирует L1D... .)   -  person Peter Cordes    schedule 25.10.2017
comment
В любом случае, это, возможно, был бы правильный выбор дизайна, но потребовалось бы больше транзисторов для проверки очереди (очередей) хранения другого потока на наличие устаревших хранилищ, а также вашей собственной очереди сохранения для всех хранилищ. Если вы хотите знать, вам придется поэкспериментировать с интересующей вас микроархитектурой, если вы не сможете найти ничего окончательного. (Или отредактируйте этот вопрос и, возможно, получите ответ, если кто-то еще знает.)   -  person Peter Cordes    schedule 25.10.2017
comment
@PeterCordes: Спасибо, я думаю, что достаточно хорошо понял задействованные механизмы. Я могу продолжить свои собственные тесты и лучше понять результаты. Очень признателен.   -  person Tyler    schedule 26.10.2017


Ответы (1)


Вы слишком усложняете это.

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

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

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

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

person old_timer    schedule 19.04.2017
comment
Что вы, надеюсь, узнаете, так это то, что бенчмаркинг — это бред, вы не получите точных результатов, ваши результаты не только должны отличаться от запуска к запуску, если вы работаете в операционной системе с несколькими ядрами, использующими общие ресурсы, но строки кеша все время удаляются, и с точки зрения программиста это кажется случайным, прерывания и другие задачи, более или менее перемещая мышь, будут влиять на то, какой код когда запускается и что находится в кеше, а что нет, что может повлиять на производительность при запуске для запуска, а также попытка предсказать производительность. - person old_timer; 19.04.2017
comment
Это не значит, что вы не можете оценить производительность с помощью кешей, предсказателей ветвлений и других вещей, просто это не тот случай, когда вы обычно можете предположить, а затем спроектировать два потока, попадающих в строку кеша, которая, как вы ожидаете, будет в кеше, когда это произойдет, а затем какова производительность в результате. Время от времени легко сделать производительность плохой или хорошей с помощью того, что кажется тонким, добавить nop в загрузочный ремешок, переупорядочить объекты в командной строке компиляции и т. д. полностью теряют свою ценность, но... - person old_timer; 19.04.2017
comment
спасибо за ваш ответ. Я разрабатываю для жесткого реального времени с голым железом и полностью работаю из кеша, за исключением передачи небольшого количества данных между ядрами, которые будут проходить через основную память. Для меня детерминированное время, от запуска к запуску, имеет решающее значение, но вы правы, я, вероятно, мог бы отбросить джиттер в этом порядке. Меня больше беспокоит потеря данных. Я предполагаю, что мое замешательство состоит в том, что я представил потоки почти как имеющие дополнительный кеш размером с одну строку кеша, с которой они будут работать и записывать обратно. Если они работают непосредственно на L1, то проблем быть не должно, верно? - person Tyler; 19.04.2017
comment
зависит от процессора это l1 в каждом ядре или l1 общий? если у каждого ядра есть свой собственный, и у вас есть одна программа/поток на ядро, тогда они владеют этим кешем. Затем, когда он попадает в общий кеш, до тех пор, пока другие действия не переносят эту строку кеша в основную память, не имеет значения, кто к ней прикасается, она находится в кеше. - person old_timer; 19.04.2017
comment
как правило, все в l1 находится в l2 для одного ядра, для общего l2 отдельные l1 могут конкурировать за пространство l2 и удары, но та же история, если вы получаете промах l1 и попадание l2, тогда не имеет значения, кто это. Теперь у вас есть проблема когерентности, с которой нужно иметь дело, если потоки, которым необходимо совместно использовать данные, не используют один и тот же L1, и это, скорее всего, чип/архитектура, в зависимости от того, как это решить. - person old_timer; 19.04.2017
comment
в конце концов, кеш лишь немного умнее, чем память, которая действительно глупа, кеш просто выполняет поиск тегов и определяет, есть ли у него копия или нужно получить копию (или нужно сохранить свою копию). Это не умнее, остальное определяет программатор и процессор и его особенности. поэтому вам нужно выяснить, насколько велика строка кеша, если это важно для вас, если все находится в кеше, тогда просто работайте с таким количеством килобайт адресного пространства, и вы золоты (кроме когерентности) - person old_timer; 19.04.2017
comment
Каждое ядро ​​имеет свои L1, L2 и L3. Мне не нужно беспокоиться о том, что потоки на отдельных ядрах загрязняют области памяти друг друга, об этом позаботились, но в настоящее время я принимаю решения о расположении областей памяти для нескольких потоков, совместно использующих ядро. В настоящее время данные, используемые в потоках 1 и 2 одного и того же ядра, могут чередоваться в памяти, а не разделяться - пытаясь решить, проблематично ли это. Размер строки кэша составляет 128 байт, поэтому я определенно могу иметь более одного фрагмента данных в строке. - person Tyler; 19.04.2017
comment
Этот ответ ложный. Кэш L1D сам по себе прост, да; Что делает его сложным (и проблемой производительности), так это то, что каждый логический поток на ЦП SMT имеет отдельную очередь сохранения. stackoverflow.com/questions/45602699/. Хранилища помещаются в очередь хранения при выполнении и фиксируются в L1D только после вывода из эксплуатации. Нагрузки исследуют очередь хранилища, а также L1D. В x86 правила заказа требуют общего заказа в магазине, поэтому не разрешается позволять родственному HT видеть магазин раньше. Ни увидев его перед выходом на пенсию ни на каком ISA. - person Peter Cordes; 29.08.2017
comment
Этот ответ, кажется, кэширует в основном неправильно и даже не начинает решать фактический вопрос о потоках на одном и том же ядре, которое в основном вообще не имеет ничего общего с кэшами (поскольку одноуровневые потоки разделяют все уровни кеш). - person BeeOnRope; 29.08.2017