В идеале масштабируемая система при добавлении новых процессоров должна сохранять одну и ту же среднюю пропускную способность в расчете на один процессор и постоянное среднее время запаздывания. На практике сохранение
достаточной пропускной способности каждого процессора осуществимо, но время запаздывания с увеличением числа процессоров растет. Лучше всего было бы сделать так, чтобы она росла логарифмически, как в гиперкубе.
Дело в том, что время запаздывания часто является фатальным в отношении производительности мелкомодульных и среднемодульных приложений. Если программе требуются данные, которых нет в ее локальной памяти, на их получение требуется существенное время, причем чем больше система, тем больше получается задержка. Эта проблема характерна и для мультипроцессоров, и для мультикомпьютеров, поскольку в обеих архитектурах физическая память разделена на фиксированные распределенные модули.
Системные разработчики применяют несколько технологий, позволяющих сократить или, по крайней мере, замаскировать время запаздывания. Первая технология — это репликация. Если реплики блока данных можно хранить в нескольких местах, то скорость доступа к этим данным можно повысить. Один из возможных вариантов — использование кэша, когда одна или несколько копий блоков данных хранятся рядом с местом, в котором они могут понадобиться и которому они «принадлежат». Другой вариант — хранить несколько равноправных копий (в противоположность неравноправным отношениям главная-подчиненная, характерным для основной памяти и кэш-памяти). Когда сохраняется несколько копий, главные вопросы — это кем, когда и куда они помещаются. Здесь возможны самые разные варианты, от аппаратного динамического размещения данных по запросу до их принудительного размещения во время загрузки с помощью соответствующих директив компилятора. В любом случае на первый план выходит задача согласованного управления.
Вторая технология — маскирование времени запаздывания путем так называемой упреждающей выборки (prefetching), при которой элемент данных вызывается еще до того, как он понадобится. Это позволяет перекрыть процесс вызова и процесс выполнения, так как программа получает затребованный элемент данных без задержки. Упреждающая выборка может быть реализована как аппа-ратно, так и программно. В случае упреждающей выборки в кэш загружается не только нужное слово, но и вся содержащая его строка кэша в расчете на то, что другие слова из этой строки пригодятся в будущем.
Упреждающей выборкой можно управлять и непосредственно. Когда компилятор выясняет, что программе в ходе выполнения потребуются те или иные данные, он вставляет в код команду их получения, причем с таким расчетом, чтобы получить нужные данные вовремя. Такая стратегия требует, чтобы компилятор обладал полными знаниями о машине и механизме ее синхронизации, а также контролировал место хранения всех данных. Спекулятивные команды LOAD работают лучше всего, когда абсолютно точно известно, что загруженные данные будут использованы. Ошибка отсутствия страницы при выполнении команды LOAD для ветви, которая никогда не понадобится, — дело чрезвычайно затратное.