Во-первых, и компилятор, и сам процессор уже настойчиво переупорядочивают инструкции, чтобы максимально эффективно использовать ILP. Скорее всего, они справляются с этим лучше, чем вы когда-либо сможете.
Однако есть несколько областей, в которых человек может помочь процессу.
Компилятор обычно очень консервативен при переупорядочении вычислений с плавающей запятой, потому что это может немного изменить результат. Так, например, предполагая этот код:
float f, g, h, i;
float j = f + g + h + i;
вы, вероятно, получите нулевой ILP, потому что код, который вы написали, оценивается как ((f + g) + h) + i
: результат первого добавления используется как операнд для следующего, результат которого используется как операнд в последнее дополнение Два дополнения не могут выполняться параллельно.
Если вместо этого записать его как float j = (f + g) + (h + i)
, ЦП может выполнять f+g
и h+i
параллельно. Они не зависят друг от друга.
В целом, что мешает ILP - это зависимости. Иногда они являются прямыми зависимостями между арифметическими инструкциями, как указано выше, а иногда они являются зависимостями хранения / загрузки.
Загрузка и сохранение выполняются долго по сравнению с операциями в реестре, и зависящие от них операции должны будут ждать завершения операции загрузки / сохранения.
Таким образом, хранение данных во временных файлах, которые компилятор может кэшировать в регистрах, иногда может использоваться для предотвращения доступа к памяти. Аналогичным образом, запуск загрузок как можно быстрее также помогает избежать задержек при блокировании следующих операций.
Лучшая техника - это внимательно присмотреться к вашему коду и проработать цепочки зависимостей. Каждая последовательность операций, каждая из которых зависит от результата предыдущего, представляет собой цепочку зависимостей, которые никогда не могут выполняться параллельно. Можно ли каким-то образом разорвать эту цепь? Возможно, путем сохранения значения во временном файле или путем повторного вычисления значения вместо ожидания загрузки кэшированной версии из памяти. Возможно, просто поместив несколько скобок, как в оригинальном примере с плавающей точкой.
Когда нет никаких зависимостей, ЦПУ будет планировать операции для параллельного выполнения. Поэтому все, что вам нужно сделать, чтобы использовать ILP, это разорвать длинные цепочки зависимостей.
Конечно, легче сказать, чем сделать ...:)
Но если вы проведете некоторое время с профилировщиком и изучите вывод сборки компилятором, иногда вы можете добиться впечатляющего ускорения от ручной оптимизации кода для лучшей эксплуатации ILP.