программная предвыборка осуществляется следующими
В процессорах P-III и P- 4 программная предвыборка осуществляется следующими инструкциями: prefetchnta, prefetcht0, prefetcht1, prefetcht2. Суффикс указывает на тип загружаемых данных, что определяет уровень кэш-иерархии, в которую эти данные будут загружены. Так, "NTA" расшифровывается как "Non-TemporAl [Data]" – не временные данные, т.е. данные, многократное использование которых не планируется. Соответственно "T0", "T1" и "T2" обозначает временные данные, использовать которые планируется неоднократно.
Какой бы командной предвыборка ни осуществлялась, кэш - линейкам, загружаемым из основной памяти, всегда присваивается эксклюзивный
статус. При предвыборке линеек из кэша второго уровня, их прежний статус сохраняется. Возможность загрузки кэш-линейки с автоматической установкой статуса модифицируемой в процессорах Pentium не реализована. Однако ввиду многоступенчатой схемы буферизации записи, изменение атрибутов кэш-линеек происходит в основном, а не дополнительном, как в K6\Athlon, цикле обмена, т.е. без ущерба для производительности.
Причем, в отличие от prefetch/w, инструкции prefetchnta/t0/t1/t2 не приказывают, а рекомендуют (или, если так угодно, – просят) осуществить предвыборку. Процессор отклоняет просьбу и не осуществляет предвыборку, если:
· запрошенные данные уже содержится в кэше соответствующей или ближайшей к процессору иерархии;
· сведения о станице, к которой принадлежат загружаемые данные, отсутствуют в DTLB (Data Translation Look aside Buffer – Буфере Ассоциативной Трансляции);
· подсистема памяти процессора занята перемещением данных между L1- и L2-кэшем;
· запрошенные данные принадлежат региону некэшируемой памяти (странице с атрибутами UC или USWC);
· данные не могут быть загружены из-за ошибки доступа (при этом исключение не вырабатывается);
· инструкция предвыборки предваряется префиксом LOCK (в этом случае генерируется исключение "неверный опкод").
Во всех остальных случаях предвыборка выполняется. Алгоритм ее выполнения аппаратно - зависим и сильно варьируется от одной модели процессора к другой, поэтому, поведение "предвыборных" команд на P-III и P-4 ниже рассматривается по отдельности.
Pentium-III:
Инструкция prefetchnta
загружает данные в кэш первого уровня, минуя кэш-второго. Действительно, данные, повторное обращение к которым не планируется, целесообразно помещать в кэш самой ближайший к процессору иерархии, не затирая содержимое остальных, т.к. оно может еще пригодиться, а вот однократно используемые данные после их вытеснения из L1-кэша, из L2-кэша затребованы уж точно не будут.
Инструкция prefetcht0
загружает данные в кэш иерархии обоих уровней. Данные, обращение к которым происходит многократно, будучи загруженными в L2-кэш, окажутся как нельзя кстати, когда будут вытеснены из L1-кэша.
Инструкции prefetcht1 и prefetcht2
загружают данные в один лишь кэш второго уровня, не помещая их в кэш первого. Поскольку, выгрузка буферов записи происходит в кэш второго уровня, минуя первый, то предвыборку соответствующих линеек в L1-кэш осуществлять нецелесообразно. Вот тут-то и пригодится prefetcht1/t2!
Размер загружаемых данных равен длине кэш-линеек соответствующей иерархии и составляет 32 байта.
Pentium-4:
Ни одна из команд предвыборки P-4 не позволяет загружать данные в кэш первого уровня. Все – и временные, и не временные данные помещаются лишь в кэш второго уровня, поскольку… поскольку, создатели процессора захотели поступить именно так. Эффективность такой стратегии дискуссионна, но, как бы там ни было, время доступа к кэшу второго уровня, намного меньше времени доступа к оперативной памяти, поэтому, даже такая предвыборка все же значительно лучше, чем ничего.
Возникает вопрос – если все команды предвыборки помещают загружаемые данные в кэш второго уровня, то какая между ними разница? Между командами prefetcht0, prefetcht1 и prefetcht2 – действительно, никакой.
А вот команда prefetchnta
отличается тем, что помещает загружаемые данные не в любой, а исключительно в первый банк кэша второго уровня (восьми ассоциативный L2-кэш P-4 содержит восемь таких банков), благодаря чему prefetchnta
никогда не вытесняет более 1/8 объема кэша второго уровня. Однократно используемые данные, как уже говорилось выше, действительно, не должны вытеснять многократно используемые данные из верхних кэш-иерархий, но в P-4 такое вытеснение все же происходит, и предотвратить его, увы, нельзя. Причем, вытесняются отнюдь не те ячейки, к которым дольше всего не было обращений, а линейки фиксированного банка, возможно интенсивно используемые обрабатываемым их приложением! Словом, в P-4 программная предвыборка реализована далеко не лучшим образом – непродуманно, что называется "спустя рукава". (Не иначе как дикая конкурентная спешка дает о себе знать).
Размер загружаемых данных равен длине линеек кэша второго уровня, что составляет 128 байт.
Различия в реализации предвыборки на P-III и P-4 существенно затрудняют оптимизацию приложений, поскольку каждый процессор требует к себе особого, индивидуального подхода и одновременно угодить всем им невозможно. Для достижения максимальной эффективности все критические процедуры рекомендуется реализовывать как минимум в двух вариантах – отдельно для P-III и отдельно для P-4. В противном случае, либо P?III будет зверски тормозить, либо P-4 не раскроет подлинного потенциала своей производительности. Учитывая существование K6\Athlon процессоров, вариантов реализации набирается уже четыре. Не слишком ли много головной боли для программистов? Нет, это вовсе не призыв к отказу от предвыборки, – в ряде случаев такой отказ просто невозможен. Это всего лишь незлобное ворчание замученного программиста… (А программисты, как и комсомольцы, легкими путями не избалованы).