Введение

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

Истинная зависимость (читать после записи)

Истинная зависимость, также известная как зависимость потока или зависимость данных, возникает, когда инструкция зависит от результата предыдущей инструкции. Нарушение истинной зависимости приводит к конфликту "чтение после записи" (RAW). 1. A = 3 2. B = A 3. C = B

Инструкция 3 истинно зависит от инструкции 2, поскольку конечное значение C зависит от инструкции, обновляющей B. Инструкция 2 истинно зависит от инструкции 1, поскольку конечное значение B зависит от инструкции, обновляющей A. Поскольку инструкция 3 истинно зависит от инструкции 2, а инструкция 2 истинно зависит от инструкции 1, инструкция 3 также истинно зависит от инструкции 1. Следовательно, параллелизм на уровне инструкций невозможен в данном примере.

Зависимость от выхода (запись-после-записи)

Зависимость по результату возникает, когда порядок выполнения инструкций влияет на конечное значение переменной. Нарушение зависимости по результату приводит к конфликту записи после записи (WAW). В приведенном ниже примере существует зависимость по результату между инструкциями 3 и 1 — изменение порядка этих инструкций изменит конечное значение A, следовательно, они не могут быть выполнены параллельно. 1. B = 3 2. A = B + 1 3. B = 7 Как и антизависимости, зависимости по результату являются зависимостями по имени. То есть, они могут быть устранены путем переименования переменных, как показано в следующей модификации приведенного выше примера: 1. B2 = 3 2. A = B2 + 1 3. B = 7

Последствия

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

Актуальность в вычислительной технике

Зависимости данных актуальны в различных областях информатики, в частности, при проектировании процессоров, разработке компиляторов, параллельных вычислениях и конкурентном программировании.

Конструкция процессора

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

Конструкция компилятора

Зависимости данных важны для различных оптимизаций компилятора, например:

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