Ответ 1
Изменить: (я удаляю сведения о restrict
, потому что он отклоняется от заданного вопроса и вызывает путаницу. OP предполагает, что используется restict
.)
Преобразование в вашем вопросе действительно тривиально для оптимизирующего компилятора, но это не то, что предлагает бумага Актона.
Вот трансформация, сделанная в документе:
Этот код...
for (size_t i=0;i<count*stride;i+=stride)
{
velocity_x[i] += acceleration_x[i] * time_step;
velocity_y[i] += acceleration_y[i] * time_step;
velocity_z[i] += acceleration_z[i] * time_step;
position_x[i] += velocity_x[i] * time_step;
position_y[i] += velocity_y[i] * time_step;
position_z[i] += velocity_z[i] * time_step;
}
... был преобразован в этот код:
for (size_t i=0;i<count*stride;i+=stride)
{
const float ax = acceleration_x[i];
const float ay = acceleration_y[i];
const float az = acceleration_z[i];
const float vx = velocity_x[i];
const float vy = velocity_y[i];
const float vz = velocity_z[i];
const float px = position_x[i];
const float py = position_y[i];
const float pz = position_z[i];
const float nvx = vx + ( ax * time_step );
const float nvy = vy + ( ay * time_step );
const float nvz = vz + ( az * time_step );
const float npx = px + ( vx * time_step );
const float npy = py + ( vy * time_step );
const float npz = pz + ( vz * time_step );
velocity_x[i] = nvx;
velocity_y[i] = nvy;
velocity_z[i] = nvz;
position_x[i] = npx;
position_y[i] = npy;
position_z[i] = npz;
}
Что такое оптимизация?
Оптимизация не - как было предложено - разделение 1 выражения на 3 выражения.
Оптимизация - это вставка полезных инструкций между инструкциями, которые работают с какой-либо конкретной частью данных.
Если вы переходите от данных, перемещающихся с velocity_x[i]
до vx
в nvx
обратно на velocity_x[i]
, CPU выполняет другую работу между каждым из этих шагов.
Почему это оптимизация?
Современные процессоры обычно имеют конвейерную архитектуру .
Поскольку инструкции выполняются поэтапно, процессор позволяет обрабатывать несколько инструкций одновременно. Однако, когда инструкция требует результата другой инструкции, которая не была полностью выполнена, этот конвейер застопорился. Никакие дальнейшие инструкции не выполняются до тех пор, пока не будет запущена команда остановки.
Почему мой оптимизирующий компилятор не делает это автоматически?
Некоторые делают.
GCC выделяется относительно плохо с этой оптимизацией.
Я разобрал обе петли выше, используя gcc 4.7 (архитектура x86-64, оптимизация при -O3). Аналогичная сборка была произведена, но порядок инструкций был другим, и в первой версии были выпущены значительные киоски, где один поплавок был загружен, изменен и сохранен в пределах нескольких инструкций.
Вы можете немного прочитать о расписании команд gcc здесь или просто найти в Интернете для планирования команд gcc, чтобы увидеть много разочарованных статей об этой проблеме.