Введение
Прошлый 2005 год ознаменовался началом массового повсеместного появления и внедрения двухъядерных процессоров в настольные компьютеры. Двухъядерные процессоры представляют собой два расположенных на одной кремниевой пластине полноценных процессорных ядра с полным набором ресурсов, в том числе с кэш-памятью первого уровня (L1D). Кэш-память второго уровня (L2) может быть раздельной для каждого ядра или общей для обоих ядер. На той же подложке может располагаться контроллер шины памяти, контроллер межъядерных коммуникаций, коммутатор и т.п. Многочисленные тестирования показывают преимущества двухъядерных процессоров над одноядерными в ряде задач, поддерживающих многопоточную работу. Но до сих пор не было ни одного тестирования, проливающего свет на то, с какой скоростью ядра могут обмениваться данными.
Взаимодействие процессоров в многопроцессорных системах
Для понимания материала статьи вспомним, какие проблемы встают при взаимодействии процессоров в многопроцессорной системе.
Процессоры работают с данными, которые читаются из оперативной памяти, изменяются и записываются назад в память. Данные, прочитанные из оперативной памяти, кэшируются в процессоре, что значительно ускоряет обработку данных. В многопроцессорной системе к одним и тем же данным может одновременно обращаться более чем один процессор. Если оба процессора читают данные, то проблем не возникает, так как оба процессора получают последние действительные данные из оперативной памяти. Если хоть один из процессоров данные меняет, то данные сначала изменяются в кэш-памяти и лишь много позже могут быть выгружены в оперативную память. При этом возникают потенциальные конфликтные ситуации, если один из процессоров пытается считывать из оперативной памяти данные, которые изменены и находятся в кэш-памяти другого процессора.
Методы решения конфликтов, происходящих при обращении к общим данным, называются протоколами поддержания когерентности кэш-памяти. Существует несколько разновидностей таких протоколов, но описание принципов их работы выходит за рамки данной статьи, поэтому более детально читатель может ознакомиться с ними самостоятельно в других источниках (например, о них можно почитать в
этой статье, а также в
документации производителей процессоров).
Все разновидности протоколов поддержания когерентности кэш-памяти для обмена изменившимися данными между процессорами обычно используют оперативную память. Но ядра в двухъядерных процессорах расположены на одной подложке в непосредственной близости друг от друга, что предоставляет потенциальную возможность прямой передачи данных из кэша одного ядра в кэш другого, то есть обмен данными между ними должен происходить максимально быстро. Это даёт основание многим авторам в статьях и обзорах в компьютерных изданиях высказывать предположения, что суммарный эффективный объём кэшей двух раздельных ядер можно приравнять к одному общему. Справедливо ли такое предположение? Целью данного исследования является поиск ответа на этот вопрос.
Как мы будем тестировать?
Для оценки скорости доступа в кэш соседнего ядра был разработан алгоритм, реализующий использование общего блока данных двумя потоками. В тестирующей программе созданы два рабочих потока, каждый из которых жёстко назначается одному из логических процессоров. Первый поток работает с блоком данных в памяти в двух режимах:
только-чтение, в котором данные просто закачиваются из оперативной памяти в кэш, и
чтение-с-изменением, в котором данные после закачки модифицируются. Таким образом, мы проверяем два случая:
1. последняя копия данных находится в оперативной памяти и в кэше второго процессора;
2.последняя копия данных находится только в кэше второго процессора, а в оперативной памяти находятся недействительные данные.
После операции с данными первый поток передаёт управление второму потоку, ожидающему сигнала, а сам переходит в ожидающее состояние. Второй поток считывает этот же блок данных, измеряя задержку чтения.
Так как при считывании данных вторым потоком они могут кэшироваться процессорным ядром, то обычный метод повышения точности измерения задержки путём многократного прогона теста по одному и тому же участку памяти здесь не применим. Поэтому второму потоку приходится очищать свой кэш от загруженных данных применением команды CFLUSH к каждой строке кэш-памяти, содержащей считанные данные, и передавать управление назад первому потоку для повторной закачки данных. В дальнейшем по тексту для облегчения восприятия будем называть ядро, на котором выполняется первый поток, закачивающий в кэш данные из памяти, первым ядром, а ядро, на котором работает поток, измеряющий скорость получения данных из первого ядра, вторым ядром.
Синхронизация потоков выполняется так называемыми spin-wait циклами (Простой цикл вида
while(!signal);. Переменная signal должна быть модифицирована извне другим потоком.) в обоих потоках. Эти циклы, во-первых, обеспечивают максимальную скорость передачи управления одному потоку по сигналу другого и, во-вторых, удерживают процессор за потоком, не позволяя чужим потокам запуститься на нём, изменив содержимое кэшей. Оба потока при этом работают с высочайшим приоритетом THREAD_PRIORITY_REALTIME.
Для измерения скорости получения данных во втором потоке используется цепочка связных указателей, разделённых другими командами для задержки использования прочитанных данных:
// eax – начало блока данных
xor ebx, ebx // ebx <=0
xor edx,edx // edx <=0
……..
and edx, eax // синхронизация
mov eax, [eax+ebx]// чтение данных
N*{and ebx, edx} // задержка использования прочитанных данных
and edx, eax // синхронизация момента использования прочитанных данных
mov eax, [eax+ebx] // использование прочитанных данных, новое чтение данных
N*{and ebx, edx}
and edx, eax
mov eax, [eax+ebx]
…….. В этой цепочке N – количество команд задержки. Задержка обеспечивает подстройку под побочные эффекты спекулятивного исполнения, такие как реплей, позволяя проанализировать зависимость скорости получения запрошенных данных от длины цепочки и получить представление о характеристиках системы памяти. Команда синхронизации обеспечивает заданный порядок команд задержки, не давая процессору переупорядочивать команды чтения в цепочке.
Для тестирования возьмём размеры блоков данных от 8 КБ до 4096 МБ, растущие с шагом степени двойки, что позволит нам охватить в тестировании широкий диапазон вариантов – от данных, целиком помещающихся в кэше L1, до данных, не помещающихся в кэш ни одного из протестированных процессоров. Обход данных внутри блока осуществляется с шагом 64 байта.
AMD Athlon 64 X2
Первым в нашем тестировании станет двухъядерный процессор AMD Athlon 64 X2, имеющий рейтинг 4400+, с кэш-памятью второго уровня по 1024 КБ отдельно на каждом ядре и работающий на частоте 2200 МГц. Оба ядра в процессоре не только расположены на общей кремниевой подложке, но и подключены через системный интерфейс запросов (System Request Interface) к коммутатору (Crossbar switch), через который проходят все запросы к данным в оперативной памяти, поэтому мы вправе ожидать, что взаимодействие ядер между собой происходит без дополнительной нагрузки на системную шину и шину памяти.
Начнём тестирование со случая, когда первый поток считывает данные, но не модифицирует их, то есть и в оперативной памяти, и в кэше процессора первого потока находится одна и та же копия данных.
Рис. 1. AMD Athlon 64 X2. Последовательное чтение немодифицированных
данных, загруженных в кэш другого ядра Рис. 2. AMD Athlon 64 X2. Чтение в случайном порядке немодифицированных
данных, загруженных в кэш другого ядра На графиках показаны зависимости средней скорости получения данных от длины цепочки задержки. С первого же графика (рис. 1) видно, что при последовательном доступе минимально наблюдаемая задержка практически не зависит от размера выбираемого блока и равна примерно 50 тактам вне зависимости от ожидаемого местонахождения данных, что свидетельствует о том, что данные всегда берутся из памяти. Наблюдаемые 50 тактов не являются латентностью оперативной памяти – это среднее время получения данных с учётом аппаратной предвыборки.
При случайном доступе (рис. 2) графики выглядят интереснее. Во-первых, минимальная наблюдаемая латентность разная для разных размеров блоков и уменьшается с уменьшением блока. Но минимальная латентность свыше 80 тактов выглядит слишком высокой для доступа в кэш, пусть даже чужой, и латентность доступа к данным, целиком помещающимся в одном уровне кэш-памяти, не должна так сильно различаться в зависимости от объёма. Это наводит на подозрение, что и здесь влияет предвыборка. Мы проверим это позже.
Во-вторых, на графиках с ростом длины цепочки наблюдается ступенчатое увеличение латентности, которое хорошо заметно, начиная с блока данных размером 16 Кб, и характерно также для блока размером 4 МБ, когда ни о каком попадании в кэш речь идти не может. Высота ступеньки равна 10 тактам. Коэффициент умножения данного процессора тоже равен 10. Напрашивается мысль, что ступенчатая структура графика связана с темпом прибытия данных из внешней к процессору памяти. Мы тоже это обязательно проверим.
Итак, наблюдаемые результаты чтения немодифицированных данных пока наводят на мысль, что никакого быстрого чтения данных из кэша второго ядра не происходит. Что ж, возможно, таковы особенности реализации протокола MOESI, запрашивающего последнюю действительную копию данных из памяти. Посмотрим, может быть, с модифицированными данными, последняя копия которых должна находиться в кэше первого ядра, нам повезёт больше.
Рис. 3. AMD Athlon 64 X2. Последовательное чтение данных, модифицированных
в кэше другого ядра Рис. 4. AMD Athlon 64 X2. Чтение в случайном порядке данных, модифицированных
в кэше другого ядра Результаты не радуют. Мы видим, что абсолютные значения задержки получения данных ещё несколько выросли, при этом картина качественно не изменилась. Латентность доступа к данным второго потока слишком высока для возможного прямого чтения из кэш- памяти первого ядра. При случайном чтении модифицированных данных (рис. 4) обращает на себя внимание небольшой рост задержки получения данных для блоков данных размером до 512 КБ, что может быть связано с необходимостью копирования модифицированных строк из кэша процессора в память. Но рост задержки несильный. При последовательном доступе роста задержки вообще практически не наблюдается, что, возможно, говорит о том, что для считывания только что записанных в память модифицированных данных контроллер памяти не делает второго обращения, а возвращает процессору данные из внутренних буферов, что, в общем-то, правильно.
Чтобы окончательно выяснить, что мы считываем данные именно с системной шины, проведём пару тестов.
Сначала уменьшим коэффициент умножения процессора с 10 до 6, что соответствует его работе на частоте 1200 МГц. Посмотрим на результаты случайного чтения модифицированных данных.
Рис. 5. AMD Athlon 64 X2, частота 1200 МГц. Чтение в случайном порядке
данных, модифицированных в кэше другого ядра "Высота" ступенек теперь стала равна 6. Это однозначно указывает на то, что передача данных в ядро синхронизирована с шиной памяти процессора, то есть скорее всего идёт через неё.
Теперь проверим нашу версию того, что данные читаются именно из оперативной памяти, измерив время чтения данных из памяти. Для этого просто отключим чтение данных первым потоком. Таким образом, в данном варианте теста с данными работает только второй поток в следующем режиме: чтение данных из оперативной памяти с измерением времени, затем очистка кэша и снова чтение данных и очистка кэша.
Рис. 6. AMD Athlon 64 X2. Последовательное чтение данных из оперативной
памяти Рис. 7. AMD Athlon 64 X2. Чтение из оперативной памяти данных в случайном
порядке Графики при чтении немодифицированных данных, загруженных в первое ядро (рис. 1, 2), и при чтении данных из оперативной памяти (рис. 6, 7) практически полностью совпадают, что говорит о том, что версия о влиянии на задержку при случайном доступе алгоритма аппаратной предвыборки данных была верной! Отличия есть только в графиках задержки для блоков размером 8-16 КБ, но они связаны с работой алгоритма аппаратной предвыборки данных, в чём мы сможем убедиться, если будем запускать тесты несколько раз.
К сожалению, остаётся констатировать факт. Никакой прямой передачи данных из ядра в ядро в процессоре Athlon 64 X2 обнаружить не удалось, последняя копия данных, судя по результатам нашего исследования, всегда считывается из памяти. По всей видимости, это ограничение реализации протокола MOESI. Скорее всего, при обращении к данным происходит следующее: получив запрос чтения
probe read, который выставляет на системную шину второе ядро, первое ядро выполняет обратную запись (
write back) модифицированной строки из кэша в память, после записи в память или одновременно с ней запрошенная строка передаётся во второе ядро. В случае, если данные в кэше первого ядра не были модифицированы, то происходит считывание данных из оперативной памяти. Что мешает сделать прямую передачу данных (
bypass) через коммутатор (
crossbar) между ядрами? Об этом нужно спросить инженеров AMD. :)
Двухпроцессорная система на Opteron
Думается, многим читателям было бы интересно посмотреть на то, как выглядят характеристики двухпроцессорной системы на этом тесте. Прежде чем закончить с процессорами компании AMD и перейти к тестированию процессоров фирмы Intel, посмотрим на результаты тестирования двухпроцессорной платформы с двумя чипами Opteron 254, работающими на частоте 2800 Мгц.
Рис. 8. Двухпроцессорная система AMD Opteron. Последовательное чтение
немодифицированных данных, загруженных в кэш другого процессора Рис. 9. Двухпроцессорная система AMD Opteron. Чтение в случайном порядке
немодифицированных данных, загруженных в кэш другого процессора Рис. 10. Двухпроцессорная система AMD Opteron. Последовательное чтение
данных, модифицированных в кэше другого ядра Рис. 11. Двухпроцессорная система AMD Opteron. Чтение в случайном порядке
данных, модифицированных в кэше другого ядра Результаты качественно схожи с результатами тестирования Athlon 64 X2, только количественные характеристики задержек выросли, особенно при случайном доступе. Наблюдаемый аномальный разброс задержек при последовательном доступе, когда при меньшем объёме данных наблюдается большая задержка, наиболее вероятно объясняется значительной долей накладных расходов на передачу данных по Hyper Transport со стороны памяти второго процессора, что при малом объёме данных ухудшает средние показатели. Однозначно можно сказать, что на двухъядерном процессоре работа с общими данными обходится значительно дешевле (в плане снижения производительности), чем на двух одноядерных.
Pentium D
Перейдём к процессорам компании Intel. Первым в нашем тестировании будет процессор Pentium D 920, основанный на ядре Presler. Процессор работает на частоте 2800 МГц и обладает двумя ядрами с 2 МБ кэш-памяти второго уровня на каждом ядре. В отличие от ядер процессора Athlon 64 X2, подключенных к общему коммутатору, через который проходят все запросы к системной шине и шине памяти, ядра процессора Pentium D подключены к общей FSB более простым способом через разделяемый интерфейс шины. Поэтому после изучения скорости обмена данными между ядрами Athlon 64 X2 от тестирования Pentium D высоких показателей тоже не ожидаем. Но посмотрим на результаты тестирования.
Рис. 12. Pentium D. Последовательное чтение немодифицированных данных,
загруженных в кэш другого ядра Рис. 13. Pentium D. Чтение в случайном порядке немодифицированных
данных, загруженных в кэш другого ядра Рис. 14. Pentium D. Последовательное чтение данных, модифицированных
в кэше другого ядра Рис. 15. Pentium D. Чтение в случайном порядке данных, модифицированных
в кэше другого ядра Графики тестов в чём-то напоминают графики для Athlon 64 X2, но всё же по ним заметны некоторые микроархитектурные отличия. Ступенчатый характер доступа к памяти при случайном доступе изменился на волнистый (рис. 13, 15). Период волны равен 18 тактам, что в точности соответствует длине кольца
реплея, используемого процессорами архитектуры NetBurst для перезапуска цепочки команд при кэш-промахах и ошибках спекулятивного исполнения.
При последовательном доступе к модифицированным данным произошёл заметный и одинаковый для всех блоков данных объёмом до 2 МБ рост латентности или, если точнее, снижение темпа чтения, тогда как для блока объёмом 4 МБ наблюдаемое снижение темпа значительно меньше. Но вот при случайном доступе всё в точности наоборот – задержка доступа к модифицированным данным заметно снизилась! Судя по всему, модифицированные данные, копируемые первым ядром в оперативную память, могут быть переданы контроллером памяти во второе ядро из промежуточных буферов одновременно с записью в микросхемы памяти. Это позволяет сэкономить драгоценные такты при случайном чтении. Но при последовательном доступе темп получения данных вторым ядром всё равно ограничивается скоростью сохранения данных в память первым ядром, так как запись данных в микросхемы оперативной памяти занимает больше времени, чем чтение.
Теперь проверим нашу версию о том, что данные читаются именно из оперативной памяти, измерив время чтения данных из памяти так же, как мы это делали для процессора Athlon 64 X2.
Рис. 16. Pentium D. Последовательное чтение данных из оперативной памяти Рис. 17. Pentium D. Чтение из оперативной памяти данных в случайном порядке Результаты весьма неоднозначны. С одной стороны, по сравнению с графиками чтения немодифицированных данных, загруженных в первое ядро (рис. 12, 13), значения задержки для блоков данных до 64 КБ подросли. Особенно заметно выросли значения задержки для блоков данных 8 и 16 КБ, что соответствует размеру кэша L1D данного процессора Pentium D. С другой стороны, значения задержки на малых блоках выросли на графиках последовательного чтения (рис. 16), что никак не может быть объяснено более высокой скоростью в случае передачи данных от ядра к ядру. Значения задержки чтения блоков от 128 КБ и выше вообще практически совпадают. Это говорит о том, что данные в этих случаях однозначно читаются из оперативной памяти, а не передаются от ядра к ядру. Наиболее вероятной причиной наблюдаемого повышения задержки могут быть факторы, связанные с работой алгоритма аппаратной предвыборки или организацией алгоритма тестирования, например, увеличение накладных расходов, которые были ранее замаскированы во время работы первого ядра, относительно реальной задержки.
Pentium 4 (Prescott)
Ещё одним процессором, протестированным "вне конкурса" будет процессор Pentium 4 на ядре Prescott с тактовой частотой 3800 МГц и кэшем второго уровня 2 МБ. "Вне конкурса" – потому как это одноядерный процессор с поддержкой технологии Hyper Threading. Уверен, многим читателям было бы интересно взглянуть на результаты, показанные этим процессором на алгоритме, который мы используем для тестирования. Хотя какие там могут быть сюрпризы? Два виртуальных процессора физически являются одним и тем же ядром, что означает общие кэши первого и второго уровня и, следовательно, быстрое использование общих данных обоими потоками. Так как результаты чтения из кэша модифицированных и немодифицированных данных почти полностью совпадают, я приведу здесь в целях экономии места только два графика чтения модифицированных данных.
Рис. 18. Pentium 4 + HT. Последовательное чтение модифицированных данных Рис. 19. Pentium 4 + HT. Чтение модифицированных данных в случайном порядке Как и ожидалось, никаких сюрпризов. При чтении блоков данных, умещающихся в кэш L1D, наблюдается задержка в 4 такта, соответствующая латентности кэша первого уровня. При последовательном чтении блоков данных до 2048 КБ и случайном до 256 КБ наблюдается задержка в 22 такта, соответствующая латентности кэша второго уровня. При этом минимум, наблюдаемый при длине цепочки, равной 18 тактам, соответствует длине кольца
реплея. Наблюдаемый рост задержки при случайном чтении блоков данных от 512 КБ и выше объясняется исчерпанием размера TLB, который в данном процессоре равен 64 записям, то есть его хватает одновременно только на 256 КБ памяти. В остальном продемонстрированные результаты именно такие, как и должны быть при работе потоков на процессоре с общим кэшем.
Core Duo (Yonah)
Следующим процессором в нашем исследовании будет двухъядерный процессор Intel Core Duo T2400 с частотой 1833 МГц на ядре Yonah. Основное отличие этого процессора от других уже исследованных нами процессоров заключается в использовании общего для обоих ядер кэша второго уровня размером 2 МБ.
Общий кэш второго уровня означает, что данные, прочитанные первым ядром в кэш L2, автоматически должны быть "видны" второму ядру, что позволяет нам рассчитывать на получение очень хороших результатов. Давайте на них посмотрим.
Рис. 20. Core Duo (Yonah). Последовательное чтение немодифицированных
данных, загруженных другим ядром Рис. 21. Core Duo (Yonah). Чтение в случайном порядке немодифицированных
данных, загруженных другим ядром При чтении блока немодифицированных данных размером до 1 MB наблюдается латентность в 14 тактов, что точно соответствует латентности кэша второго уровня данного процессора. Внимательный читатель наверняка задаст вопрос: почему, несмотря на то, что размер кэша второго уровня равен 2 МБ, при чтении данных объёмом 2 МБ мы наблюдаем резкое повышение латентности? Ответ на этот вопрос связан с ограниченным размером TLB данного процессора – он равен 256 записям для 4 КБ страниц. То есть TLB одновременно может обслуживать только 1024 КБ памяти, а при обращении к новым страницам происходит достаточно дорогое по времени обращение к таблицам страниц трансляции виртуальных адресов в физические, что сказывается на измеряемом результате. Итак, результаты чтения немодифицированных данных отличные, теперь посмотрим на результаты чтения модифицированных данных.
Рис. 22. Core Duo (Yonah). Последовательное чтение данных, загруженных
и модифицированных другим ядром Рис. 23. Core Duo (Yonah). Чтение в случайном порядке данных, загруженных
и модифицированных другим ядром Здесь результаты весьма неоднозначные, попробуем с ними разобраться. Наименьшее значение задержки наблюдается при размере данных 1 МБ и растёт с уменьшением объёма, достигая максимума при объёмах данных, целиком умещающихся в кэш-память первого уровня размером 32 КБ. Аномалия теста? Нет. Присмотримся внимательно. Графики при малых объёмах, помещающихся в кэш L1, поразительно похожи на графики задержек ранее протестированного процессора Athlon 64 X2. Даже очень хорошо заметна характерная ступенчатая структура. Высота ступенек – 11 тактов, что точно соответствует коэффициенту умножения процессора. Отсюда следует поразительный вывод: доступ к модифицированным данным, расположенным в кэше первого уровня другого ядра, происходит по тем же самым принципам, что и доступ к данным в кэшах ядер процессоров Athlon 64 X2 и Pentium D. То есть последняя действительная копия данных сначала отправляется на запись в оперативную память через системную шину, а затем передаётся обратно во второе ядро. Почему так может происходить? Политика кэширования данных в кэшах первого уровня ядер Yonah – write back, что означает, что после изменения данных ядром модифицированная строка с последней копией данных находится в L1 до тех пор, пока она не будет вытеснена из кэша L1, а в L2 уже находятся недействительные данные. Скорее всего, при кэш-промахе кэша общего второго уровня второе ядро выставляет запрос чтения на системную шину, а в ответ на probe read, полученный с системной шины, первое ядро, хранящее последнюю копию данных, отправляет их на шину, а не во второе ядро. Почему нельзя было сделать прямого сохранения копии данных в кэше L2, чтобы второе ядро могло их считывать непосредственно оттуда, нам сказать сложно, возможно это потребовало бы серьёзных переделок процессора для работы с таким протоколом.
Conroe
Последним процессором, который мы исследуем, станет новейший, ещё официально не представленный компанией Intel процессор с кодовым названием Conroe. Мы протестируем инженерный образец процессора, работающий на частоте 2400 МГц и обладающий общим для обоих ядер кэшем размером 4 МБ. Посмотрим на результаты теста.
Рис. 24. Conroe. Последовательное чтение немодифицированных данных,
загруженных другим ядром Рис. 25. Conroe. Чтение в случайном порядке немодифицированных данных,
загруженных другим ядром Рис. 26. Conroe. Последовательное чтение данных, загруженных и
модифицированных другим ядром Рис. 27. Conroe. Чтение в случайном порядке данных, загруженных и
модифицированных другим ядром Первое , что бросается в глаза: результаты качественно похожи на результаты Yonah, но задержки ниже. Изучим результаты подробнее.
Во-первых, при чтении немодифицированных данных задержка получения соответствует латентности кэша второго уровня (рис. 24, 25). Что интересно, при последовательном и случайном обходах наблюдаются отличия в латентности кэша второго уровня – при последовательном обходе значение задержки около 12 тактов (рис. 24), при случайном - около 14 (рис. 25). Реальное значение латентности нам достоверно пока не известно, и причины подобного различия в поведении при разном виде доступа требуют проведения дополнительных исследований.
Во-вторых, при чтении модифицированных данных, как и у Yonah, заметно сильное повышение задержки в случае, если данные, модифицированные другим ядром, полностью помещаются в его кэш L1D, но величина задержки значительно меньше (рис. 26, 27). Так же хорошо заметна ступенчатая структура при удлинении цепочки с высотой ступени 9 тактов, что соответствует значению коэффициента умножения процессора (рис. 27).
Теперь отключим чтение данных первым потоком и проверим скорость чтения из оперативной памяти.
Рис. 28. Conroe. Последовательное чтение данных из оперативной памяти Рис. 29. Conroe. Чтение в случайном порядке данных из оперативной памяти На данном алгоритме заметно значительное повышение эффективности работы с памятью (рис. 28, 29). Более высокая скорость работы с памятью объясняет более низкие, по сравнению с Yonah, значения задержки при чтении данных, модифицированных в L1D другого ядра.
Общий вывод можно сделать такой: скорость обмена модифицированными данными в процессоре Conroe значительно выше по сравнению с Yonah, но обмен модифицированными данными, если они находятся в L1D, также происходит с использованием системной шины.
Выводы
Из всех исследованных нами процессоров ни один процессор с раздельными кэшами не смог продемонстрировать быстрый обмен данными между ядрами. Только процессоры Intel Core Duo (Yonah) и Conroe, каждый из которых обладает общим для двух ядер кэшем второго уровня, позволяют быструю одновременную работу обоих ядер с общим блоком данных, но и у них наблюдаются серьёзные ограничения в скорости работы в случаях, когда общие данные модифицируются. Таким образом, наиболее эффективное использование ресурсов двухъядерных процессоров будет происходить только при работе вычислительных потоков с различными участками памяти или с одним участком памяти, но без модификации общих данных. Также для увеличения эффективности разработчикам рекомендуется жёстко привязывать вычислительные потоки к ядрам, так как при переключении задач операционная система может менять местами потоки, что увеличивает процент кэш-промахов.
Автор выражает благодарность:
Гавриченкову Илье и Керученько Яну за помощь в организации тестирования;
Левченко Вадиму, Павлову Игорю, Озерову Сергею и Картунову Виктору за ценные советы и подсказки;
Десятниковой Марии за помощь в подготовке статьи.