2009-11-12 2 views
10
void Send(int * to, const int* from, const int count) 
{ 
    int 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); 
    } 
} 
+4

Как говорили другие, устройство Даффа. Я бы не реализовал это, если бы мне не пришлось, слишком эзотерическим/запутанным. Я предпочитаю читаемый код ;-) Хотя, если он завернут в такую ​​функцию, с хорошими комментариями/документацией, я бы использовал ее, если бы мне не пришлось ее трогать. –

+0

У меня не было бы проблем с использованием Duff's Device, где это уместно. Об этом говорят очень подробно, и самым большим комментарием должен быть URL, где он полностью обсуждается. – Jon

+2

Ничего себе - кто-то действительно беспокоил использование устройства Даффа для оптимизации, но не превратил модулю и деление на смену ??? – Aaron

ответ

17

Это Duff's Device для копирования буферов памяти.

+6

Ответы на связь плохие! –

+6

@Seth почему ответы на ссылки плохие? Раньше я никогда не слышал о устройстве Даффа, и ссылка на его статью в Википедии была довольно приятной, чтобы найти в самом голосовавшем ответе. –

+4

Связанный контент со временем исчезает. Вероятно, не большая проблема с Википедией, но обычно рекомендуется скопировать соответствующий фрагмент в ваш ответ и добавить ссылку в качестве ссылки. –

3

Читайте о Duff's Device

+2

Пожалуйста, не указывайте ссылки на ответы –

7

Этого смешения распределительного заявления и петля в то время как называется «Device Даффа». Это способ разворачивания циклов, который был оптимизацией, часто используемой в более ранние времена.

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

4

Duff's device

В computer science, Даффа является optimizedimplementation серийного экземпляра, который использует технику широко применяется в assembly language для loop unwinding. Его открытие зачислено в Tom Duff в ноябре 1983 года, который в то время работал на Lucasfilm. Это, пожалуй, самое драматичное использование case label fall-through в C programming language на сегодняшний день. Дафф не претендует на кредит для открытия концепции loop unrolling, только это определенное выражение его в С.

5

Это функционально идентичен коду ниже:

for(int i=0;i<n;i++) 
{ 
    *to++=*from++; 
} 

Разница заключается в том, что ваш код разворачивает цикл, так что для каждого 8 целых копий требуется только 1 итерация цикла. Так как нет никаких разрывов для любого из случаев, выполнение проваливается с каждой метки ярлыка на следующий.

Когда отсчет% 8 == 0, 8 копий выполняются внутри цикла для первой итерации

, когда счетчик% 8 == 7, 7 копий выполняются для первой итерации

и пр. После первой итерации с% 8 копий на каждую итерацию происходит ровно 8 копий.

Развертывая петлю таким образом, накладные расходы цикла значительно уменьшаются. Важно отметить порядок значений case (0,7,6,5,4,3,2,1), которые поддаются преобразованию в таблицу переходов компилятором.

обновление

Проблема с примерами кода, размещенных на OP является то, что значение счетчика 0 заставит 8 копий иметь место, что потенциально может привести к переполнению буфера.

+2

Ваши объяснения кажутся несколько неясными. Если я не ошибаюсь, коммутатор предназначен только для определения количества развернутых назначений для выполнения во время первой итерации (чтобы компенсировать, что длина буфера не может быть разделена на 8). – UncleBens

+0

Это правильно. Извините за облачное объяснение. –

15

Это Duff's Device. Это метод разворачивания циклов, который позволяет не добавлять дополнительный цикл исправления, чтобы справляться со временем, когда количество итераций цикла не известно, чтобы быть точным кратным коэффициенту разворачивания.

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

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

Статья в Википедии, на которую ссылаются другие, даже говорит, что когда этот «шаблон» был удален из исходного кода исходного кода Xfree86, фактически улучшилось.

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

Это прекрасно, что бы понять это, но я был бы удивлен, если бы вы когда-либо использовали его.

+0

+1 для этого приятного комментария на фоне. –

+1

+1 за то, что вы дали правильное мнение об этой уродливой неясной вещи. Каждый должен знать, почему * не * использовать его. –

Смежные вопросы