Jump to content

Устройство Даффа

В C языке программирования устройство Даффа представляет собой способ ручной реализации развертывания цикла путем чередования двух синтаксических конструкций C: делать - Цикл while и оператор переключения . Его открытие приписывают Тому Даффу в ноябре 1983 года, когда Дафф работал на Lucasfilm и использовал его для ускорения программы анимации в реальном времени.

Развертывание цикла пытается уменьшить накладные расходы на условное ветвление, необходимое для проверки выполнения цикла, путем выполнения пакета тел цикла на итерацию. Для обработки случаев, когда количество итераций не делится на приращения развернутого цикла, программисты на ассемблере обычно используют метод перехода непосредственно в середину тела развернутого цикла для обработки остатка. [ 1 ] Дафф реализовал эту технику в C, используя функцию пропускания метки регистра C для перехода в развернутое тело. [ 2 ]

Оригинальная версия

[ редактировать ]

Задача Даффа заключалась в копировании 16-битных целых чисел без знака («коротких» в большинстве реализаций C) из массива в отображаемый в памяти выходной регистр, обозначаемый в C указателем . Его исходный код на C выглядел следующим образом: [ 3 ] [ 4 ]

send(to, from, count)
register short *to, *from;
register count;
{
    do {                          /* count > 0 assumed */
        *to = *from++;
    } while (--count > 0);
}

Этот код предполагает, что начальный счет > 0 . Поскольку местом вывода является регистр, отображаемый в памяти, указатель to не увеличивается, как это требуется для копирования из памяти в память.

Если count всегда делились на восемь, развертывание этого цикла в восемь раз привело бы к следующему:

send(to, from, count)
register short *to, *from;
register count;
{
    register n = count / 8;
    do {
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
    } while (--n > 0);
}

Дафф понял, что для обработки случаев, когда число не делится на восемь, метод ассемблерного программиста перехода в тело цикла может быть реализован путем переплетения структур оператора переключателя и цикла, помещая метки регистра в точках тела цикла, которые соответствуют остатку количество/8 : [ 1 ]

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);
    }
}

Устройство Даффа аналогичным образом можно применить и с любым другим размером развернутой петли, а не только с восьмым, как в примере выше.

Механизм

[ редактировать ]

Основанное на алгоритме, широко используемом программистами, пишущими на ассемблере для минимизации количества тестов и ветвей во время копирования, устройство Даффа выглядит неуместным при реализации на C. Устройство валидно на языке C в силу двух атрибутов в C:

  1. Смягченная спецификация оператор переключения в определении языка. На момент изобретения устройства это было первое издание языка программирования C , для которого требуется только, чтобы тело переключатель должен быть синтаксически допустимым (составным) оператором, внутри которого метки случая могут появляться перед любым подвыражением. В связи с тем, что в отсутствие Break , поток управления провалится из оператора, контролируемого одним метка случая соответствует той, которая контролируется следующей, это означает, что код определяет последовательность подсчитывать копии из последовательных исходных адресов в отображаемый в памяти выходной порт.
  2. Возможность перейти в середину цикла в C.

Это приводит к тому, что в Jargon File называется «самым драматическим применением провала в C, которое когда-либо наблюдалось». [ 5 ] Провал C по умолчанию в утверждениях случая уже давно является одной из его наиболее спорных особенностей; Сам Дафф сказал: «Этот кодекс служит своего рода аргументом в этих дебатах, но я не уверен, за или против». [ 5 ]

Несмотря на то, что устройство Даффа применимо для C, оно противоречит общим рекомендациям C, таким как рекомендации MISRA . Некоторые компиляторы (например, CompCert ) ограничиваются такими рекомендациями и поэтому отвергают устройство Даффа, если не указано иное.

Упрощенное объяснение

[ редактировать ]
Функционально эквивалентная версия
с switch и while распутанный
send(to, from, count)
register short *to, *from;
register count;
{
    register n = (count + 7) / 8;
    switch (count % 8) {
        case 0: *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) {
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
    }
}

Основная идея развертывания цикла заключается в том, что количество инструкций, выполняемых в цикле, можно уменьшить за счет уменьшения количества тестов цикла, а иногда и за счет сокращения времени, затрачиваемого в цикле. Например, в случае цикла, содержащего только одну инструкцию в блочном коде, проверка цикла обычно выполняется для каждой итерации цикла, то есть каждый раз, когда выполняется инструкция. Если вместо этого в цикл поместить восемь копий одной и той же инструкции, то тест будет выполняться только каждые восемь итераций, и это может выиграть время, избегая семи тестов. Однако это обрабатывает только число итераций, кратное восьми, и для обработки оставшихся итераций требуется что-то еще. [ 1 ]

Устройство Даффа обеспечивает решение, сначала выполняя оставшуюся часть итераций, а затем повторяя столько раз, сколько необходимо, кратное восьми подобным инструкциям. Чтобы определить количество итераций остатка, код сначала вычисляет общее количество итераций по модулю восемь. Согласно этому остатку, выполнение программы затем перейдет к case За оператором следует точное количество необходимых итераций . Как только это будет сделано, все станет просто: код продолжает выполнять итерации групп по восемь инструкций; это стало возможным, поскольку оставшееся количество итераций кратно восьми. [ 1 ]

Устройство Даффа обеспечивает компактное развертывание цикла за счет использования ключевого слова case как внутри, так и вне цикла . Это необычно, поскольку содержимое оператора Case традиционно рассматривается как блок кода, вложенный в оператор Case, и читатель обычно ожидает, что он завершится до следующего оператора Case. Согласно спецификациям языка C, в этом нет необходимости; действительно, операторы case могут появляться где угодно внутри блока кода переключателя и на любой глубине; выполнение программы просто перейдет к следующему оператору, где бы он ни находился.

Производительность

[ редактировать ]

Многие компиляторы оптимизируют переход на таблицу ветвей так же, как это было бы сделано в реализации на ассемблере.

Основное увеличение скорости по сравнению с простым и понятным циклом происходит за счет раскручивания цикла , которое уменьшает количество выполняемых ветвей, которые являются дорогостоящими в вычислительном отношении из-за необходимости сбрасывать - и, следовательно, останавливать - конвейер команд . switch используется для обработки оставшейся части данных, не кратной числу развернутых операций (в этом примере развернуто восемь коротких ходов, поэтому switch автоматически обрабатывает дополнительные 1–7 коротких видео).

Такая автоматическая обработка остатка может быть не лучшим решением для всех систем и компиляторов — в некоторых случаях два цикла могут фактически работать быстрее (один развернутый цикл для выполнения основной копии, а второй цикл для обработки остатка). Проблема, похоже, сводится к способности компилятора правильно оптимизировать устройство; это также может мешать конвейеризации и прогнозированию ветвей на некоторых архитектурах. [ 6 ] Когда многочисленные экземпляры устройства Даффа были удалены с сервера XFree86 в версии 4.0, произошло улучшение производительности и заметное уменьшение размера исполняемого файла. [ 7 ] Поэтому, рассматривая этот код как оптимизацию программы , возможно, стоит провести несколько тестов , чтобы убедиться, что это действительно самый быстрый код на целевой архитектуре, на целевом уровне оптимизации, с целевым компилятором, а также взвесить риск. что оптимизированный код в дальнейшем будет использоваться на разных платформах, где это не самый быстрый код.

Для копирования из памяти в память (что, как упоминалось выше, не было первоначальным использованием устройства Даффа) стандартная библиотека C предоставляет функцию memcpy; [ 8 ] он будет работать не хуже, чем версия этого кода, копируемая из памяти в память, и может содержать оптимизации, специфичные для архитектуры, которые делают его значительно быстрее. [ 9 ] [ 10 ]

См. также

[ редактировать ]
  1. ^ Перейти обратно: а б с д Холли, Ральф (1 августа 2005 г.). «Многоразовое устройство для даффов» . Доктор Добб . Журнал доктора Добба . Проверено 18 сентября 2015 г.
  2. ^ Дафф, Том (29 августа 1988 г.). «Тема: Re: Объясните, пожалуйста!» . Лисатор . Проверено 3 ноября 2015 г.
  3. ^ «Удивительное устройство Даффа от Тома Даффа!» . doc.cat-v.org . Проверено 8 июня 2017 г.
  4. ^ Кокс, Расс (30 января 2008 г.). "research!rsc: Об устройстве Даффа и сопрограммах" . www.research.swtch.com . Проверено 24 января 2017 г.
  5. ^ Перейти обратно: а б Файл жаргона
  6. ^ Журнал USENIX Джеймса Ралстона, 2003 г. [ постоянная мертвая ссылка ]
  7. ^ Цо, Тед (22 августа 2000 г.). «Re: [PATCH] Re: Перемещение драйверов ввода, нужно несколько слов от вас» . lkml.indiana.edu . Список рассылки ядра Linux . Проверено 22 августа 2014 г. У Джима Геттиса есть замечательное объяснение этого эффекта на X-сервере. Оказывается, что с учетом прогнозов ветвей и изменения относительной скорости процессора по сравнению с памятью за последнее десятилетие, развертывание цикла практически бессмысленно. Фактически, за счет исключения всех экземпляров Duff's Device с сервера XFree86 4.0 размер сервера уменьшился на _половину_а_ _мегабайт_ (!!!) и стал загружаться быстрее, поскольку удаление всего этого лишнего кода означало, что X-сервер не так сильно терял строки кэша.
  8. ^ «memcpy — cppreference.com» . En.cppreference.com . Проверено 6 марта 2014 г.
  9. ^ Уолл, Майк (19 марта 2002 г.). «Использование предварительной выборки блоков для оптимизации производительности памяти» (PDF) . mit.edu . Архивировано из оригинала (PDF) 30 августа 2017 г. Проверено 22 сентября 2012 г.
  10. ^ Туман, Агнер (29 февраля 2012 г.). «Оптимизация подпрограмм на языке ассемблера» (PDF) . Инженерный колледж Копенгагенского университета . стр. 100 и далее . Проверено 22 сентября 2012 г.

Дальнейшее чтение

[ редактировать ]
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 7baffb64c19b4af148882f632ea708f7__1716805020
URL1:https://arc.ask3.ru/arc/aa/7b/f7/7baffb64c19b4af148882f632ea708f7.html
Заголовок, (Title) документа по адресу, URL1:
Duff's device - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)