Duff устройство в PHP не возможно? - PullRequest
1 голос
/ 12 ноября 2011

Мне сказали, что устройство duff не работает с PHP, потому что конструкция switch и case работает по-разному. Я нашел этот ответ на php.net, мой вопрос, что не так с этим устройством? Или я не поняла устройство? В моем ассемблере я могу развернуть цикл с помощью простой команды, и когда он компилируется, я получаю развернутый цикл.

<?php
$n = $ITERATIONS % 8;
while ($n--) $val++;
$n = (int)($ITERATIONS / 8);
while ($n--) {
   $val++;
   $val++;
   $val++;
   $val++;
   $val++;
   $val++;
   $val++;
   $val++;
}
?>

Ответы [ 2 ]

6 голосов
/ 12 ноября 2011

Это не устройство Даффа. Он использует специальный шаг предварительного выравнивания петли (это именно то, что устройство Даффа разработано, чтобы избежать).

В настоящем устройстве Даффа есть один раздел развернутого кода, который изначально частично пропускается switch. Этот трюк уменьшает необходимое количество кода (только до цикла) и уменьшает количество условных переходов в коде.

Код, который вы представили, представляет собой просто развернутый вручную цикл.


Развертывание петли:

Развертывание цикла - это метод оптимизации, при котором несколько итераций цикла обрабатываются одновременно. Так что вместо:

$number_of_iterations = 128;
for ($n = 0; $n !== $number_of_iterations; ++$n) {
    do_something();
}

Вы используете:

$number_of_iterations = 128;
for ($n = 0; $n !== (int)($number_of_iterations / 4); ++$n) {
    //Repeat do_something() four times.
    //Four is the "unrolling factor".
    do_something();
    do_something();
    do_something();
    do_something();
}

Преимущество этого - скорость. Условное ветвление обычно является относительно дорогой операцией. По сравнению с развернутым циклом первый цикл будет проходить через условную ветвь в четыре раз чаще.

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

$number_of_iterations = 130;
//Reduce the required number of iterations
//down to a value that is divisible by 4
while ($number_of_iterations % 4 !== 0) {
    do_something();
    --$number_of_iterations
}
//Now perform the rest of the iterations in an optimised (unrolled) loop.
for ($n = 0; $n !== (int)($number_of_iterations / 4); ++$n) {
    do_something();
    do_something();
    do_something();
    do_something();
}

Это лучше, но начальный цикл все равно излишне неэффективен. Он снова разветвляется на каждой итерации - дорогое предложение. В php это так хорошо, как вы можете получить (??).

Теперь введите устройство Даффа.

Устройство Duffs:

Вместо выполнения жесткой петли перед входом в эффективную развернутую зону, другой альтернативой является прямой переход в развернутую зону, но сначала переход на часть пути через петлю. Это называется устройством Даффа.

Теперь я переключу язык на C, но структура кода останется очень похожей:

//Note that number_of_iterations
//must be greater than 0 for the following code to work
int number_of_iterations = 130;
//Integer division truncates fractional parts
//counter will have the value which corresponds to the
//number of times that the body of the `do-while`
//will be entered.
int counter = (number_of_iterations + 3) / 4;
switch (number_of_iterations % 4) {
    case 0: do { do_something();
    case 3:      do_something();
    case 2:      do_something();
    case 1:      do_something();
            while (--counter > 0)
}

Все условные ветви в while ($number_of_iterations % 4 !== 0) из предыдущих были заменены одним вычисленным переходом (с переключателя).


Весь этот анализ основан на ошибочных представлениях о том, что уменьшение числа условных ветвей в области кода всегда приведет к значительно лучшей производительности, и что компилятор не сможет выполнять такие микро-оптимизация сама по себе, где это необходимо. В современном коде следует избегать как ручного развертывания петли, так и устройства Даффа.

2 голосов
/ 12 ноября 2011

Ваш код на самом деле не является устройством Даффа.Правильный DD должен иметь время while или do / while, которое является чересстрочным в операторе switch.

Смысл DD состоит в том, чтобы удалить этот бит вашего кода:

$n = $ITERATIONS % 8;
while ($n--) $val++;

Первый шаг Duff Device обрабатывается как GOTO в коде:

send(to, from, count)
register short *to, *from;
register count;
{
        register n = (count + 7) / 8;
        switch(count % 8) {
        case 0:      do {     *to = *from++;
        case 7:              *to = *from++;
        case 6:              *to = *from++;
        case 5:              *to = *from++;
        case 4:              *to = *from++;
        case 3:              *to = *from++;
        case 2:              *to = *from++;
        case 1:              *to = *from++;
                } while(--n > 0);
        }
}

Скажем, count % 8 оказывается равным 5. Это означает, что switch переходит к случаю 5,а затем просто проваливается до конца времени, и в этот момент он начинает выполнять работу с шагом 8.

...