Что отрабоатает быстрее?
От: temik Беларусь  
Дата: 04.05.05 08:31
Оценка:
В важном учаске кода надо произвести копирование из одного буфера в другой. что отработает быстрее?
memcpy(dest,src,size)
или
for(int i=o,i<size;i++)
dest[i]=src[i];

буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт
Re: Что отрабоатает быстрее?
От: Amon-RA  
Дата: 04.05.05 08:32
Оценка: +2 -1
Здравствуйте, temik, Вы писали:

T> В важном учаске кода надо произвести копирование из одного буфера в другой. что отработает быстрее?

T>memcpy(dest,src,size)
T>или
T>for(int i=o,i<size;i++)
T> dest[i]=src[i];

T>буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт


Странный вопрос. Конечно memcpy
Re: Что отрабоатает быстрее?
От: korzhik Россия  
Дата: 04.05.05 08:34
Оценка: +1 -1
Здравствуйте, temik, Вы писали:

T> В важном учаске кода надо произвести копирование из одного буфера в другой. что отработает быстрее?

T>memcpy(dest,src,size)
T>или
T>for(int i=o,i<size;i++)
T> dest[i]=src[i];

T>буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт


вариант с memcpy отработает намного быстрее ИМХО, ну уж даже если компилятор каким то образом соптимизирует цикл, то всё равно вариант с memcpy будет не медленнее.
Re[2]: Что отрабоатает быстрее?
От: MaximE Великобритания  
Дата: 04.05.05 09:15
Оценка: +1 -1
Amon-RA wrote:

[]

> T>буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт

>
> Странный вопрос. Конечно memcpy

На таких объемах данных будет проседать кэш, поэтому разница между memcpy и приведенным циклом может быть вообще незаметна.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[3]: Что отрабоатает быстрее?
От: sch  
Дата: 04.05.05 09:37
Оценка: +1 -2
Совсем народ уже ленивый стал.

void main() {
    char *buf1,*buf2;
    static const int size=32*1024*1024;
    
    buf1=(char *) malloc(2*size);
    buf2=buf1+size;

    DWORD t1,t2,t3;

    t1=timeGetTime();
    memcpy(buf1,buf2,size);
    t2=timeGetTime();
    for(int i=0; i<size; i++) buf2[i]=buf1[i];
    t3=timeGetTime();

    free(buf1);

    printf("t2-t1=%.3f\nt3-t2=%.3f",(t2-t1)/1000.0f,(t3-t2)/1000.0f);
}


У меня на Pentium IV 3.0:
t2-t1=0.057
t3-t2=0.078

Если делать так:
      p=buf2;
    q=buf1;
    for(int i=0; i<size; i++) *p++=*q++;


То результаты будут 0.57/0.62

Ну, а если например так:
    asm {
        mov esi,buf1
        mov edi,buf2
        mov ecx,size/4
        cld
        rep movsd 
    }


То результаты нас порадют: 0.57/0.29

И это еще без использования MMX, SSE и проч. и проч.
Re: Что отрабоатает быстрее?
От: GarryIV  
Дата: 04.05.05 09:38
Оценка:
Hello, temik!

t> В важном учаске кода надо произвести копирование из одного буфера в

t> другой. что отработает быстрее? memcpy(dest,src,size)
t> или
t> for(int i=o,i<size;i++)
t> dest[i]=src[i];

t> буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт


Я когда то сравнивал memcpy, duff device и цикл. Первые два примерно одинаково, цикл проигрывал существенно.
Posted via RSDN NNTP Server 1.9
WBR, Igor Evgrafov
Re[4]: Что отрабоатает быстрее?
От: _DAle_ Беларусь  
Дата: 04.05.05 09:43
Оценка:
Здравствуйте, sch, Вы писали:

sch>Совсем народ уже ленивый стал.



sch>Ну, а если например так:

sch>
sch>    asm {
sch>        mov esi,buf1
sch>        mov edi,buf2
sch>        mov ecx,size/4
sch>        cld
sch>        rep movsd 
sch>    }
sch>


sch>То результаты нас порадют: 0.57/0.29


sch>И это еще без использования MMX, SSE и проч. и проч.


А если оптимизацию включить?
Re[5]: Что отрабоатает быстрее?
От: sch  
Дата: 04.05.05 09:53
Оценка:
_DA>А если оптимизацию включить?
К сожалению сделать это не могу -- давно на асме не программировал, поэтому написать не могуЖ)

Но самое интересное, что такой вот код даст результаты приблизительно как у вышеприведенного ассемблерного кода:

;;;     p=(long *) buf2;
;;;     q=(long *) buf1;
;;;     for(int i=0; i<size/4; i++) *p++=*q++;

        xor       edx, edx                                      ;27.10
        ALIGN     4
                                ; LOE edx ecx ebx esi edi
.B1.6:                          ; Preds .B1.6 .B1.5
        mov       eax, DWORD PTR [ecx]                          ;27.36
        mov       DWORD PTR [ebx], eax                          ;27.31
        mov       eax, DWORD PTR [ecx+4]                        ;27.36
        mov       DWORD PTR [ebx+4], eax                        ;27.31
        mov       eax, DWORD PTR [ecx+8]                        ;27.36
        mov       DWORD PTR [ebx+8], eax                        ;27.31
        mov       eax, DWORD PTR [ecx+12]                       ;27.36
        mov       DWORD PTR [ebx+12], eax                       ;27.31
        add       ecx, 16                                       ;27.36
        add       ebx, 16                                       ;27.31
        add       edx, 4                                        ;27.25
        cmp       edx, 8388608                                  ;27.2
        jl        .B1.6         ; Prob 99%                      ;27.2


P.S. Компилятор -- Intel C++ 8.0 с копейками
Re: Что отрабоатает быстрее?
От: Chez Россия  
Дата: 04.05.05 10:49
Оценка:
Здравствуйте, temik, Вы писали:

Здесь хорошая статься с замерами и сравнениями.
Использовать лучше memcpy().

При включении оптизизации memcpy() будет как минимум не медленне чем простой цикл.

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[4]: Что отрабоатает быстрее?
От: Chez Россия  
Дата: 04.05.05 10:49
Оценка: +1
sch>И это еще без использования MMX, SSE и проч. и проч.
При оптимизации, memcpy() заменится на инлайн с использованием MMX, SSE и проч.

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re: Что отрабоатает быстрее?
От: ArtDenis Россия  
Дата: 04.05.05 11:13
Оценка:
t> for(int i=o,i<size;i++)
t> dest[i]=src[i];

Есть вероятность, что оптимизатор для цикла создаст код, аналогичный коду memcpy.

А без оптимизации — всё зависит от платформы Под intel — однозначно memcpy будет быстрее.
Posted via RSDN NNTP Server 1.9
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[4]: Что отрабоатает быстрее?
От: MaximE Великобритания  
Дата: 04.05.05 11:25
Оценка:
sch wrote:

> Совсем народ уже ленивый стал.


[]

> У меня на Pentium IV 3.0:

> t2-t1=0.057
> t3-t2=0.078

Зависит от компилятора. На gcc разницы между memcpy и циклом, где копируются int'ы, нет.
На Intel 8 С++ memcpy быстрее цикла в 3 раза.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[4]: Что отрабоатает быстрее?
От: SWW Россия  
Дата: 04.05.05 11:45
Оценка:
sch>У меня на Pentium IV 3.0:
sch>t2-t1=0.057
sch>t3-t2=0.078

sch>Если делать так:

sch>
sch>      p=buf2;
sch>    q=buf1;
sch>    for(int i=0; i<size; i++) *p++=*q++;
sch>

sch>То результаты будут 0.57/0.62

sch>Ну, а если например так:

sch>
sch>    asm {
sch>    }
sch>

sch>То результаты нас порадют: 0.57/0.29

Это все, конечно, в дебуге?
В релизе такие результаты (при каждом запуске результат разный, поэтому привожу диапазон):

1). memcpy (0.26 ... 0.31)

2). buf2[i]=buf1[i]; (0.31 ... 0.35)

2). *p++ = *q++; (0.28 ... 0.34)

3). rep movsd (0.22 ... 0.26)
Re[5]: Что отрабоатает быстрее?
От: sch  
Дата: 04.05.05 13:35
Оценка:
SWW>1). memcpy (0.26 ... 0.31)
Это все в релизе. Но фреймворк у меня от VC++ 6.0, на нем стоит IC++ 8.0
Re[2]: Что отрабоатает быстрее?
От: Antikrot  
Дата: 04.05.05 13:57
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>А без оптимизации — всё зависит от платформы Под intel — однозначно memcpy будет быстрее.

Под intel — все очень просто: там оптимизированный вариант memcpy (вопрос только, будет ли оптимизированный вариант memcpy использоваться при выключенной оптимизации) использует movnt* команды — как раз чтобы избавиться от проблем с кешем, про которые упомянул MaximE. Так что да, в этом случае memcpy однозначно лучше.
Re: Что отрабоатает быстрее?
От: Xander Zerge Россия www.zerge.com
Дата: 05.05.05 19:25
Оценка:
Здравствуйте, temik, Вы писали:

T> В важном учаске кода надо произвести копирование из одного буфера в другой. что отработает быстрее?

T>memcpy(dest,src,size)
T>или
T>for(int i=o,i<size;i++)
T> dest[i]=src[i];

Посмотрите, пожалуйста, во что развернётся макрос memcpy и вопрос будет снят.
Если лень, то макрос разворачивается в хитрый асм, быстрее которого придумать ничего не удастся.
Серёжа Новиков,
программист
Re[2]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 06.05.05 02:50
Оценка:
Здравствуйте, ArtDenis, Вы писали:

t>> for(int i=o,i<size;i++)

t>> dest[i]=src[i];

AD>Есть вероятность, что оптимизатор для цикла создаст код, аналогичный коду memcpy.


Нету вероятности. Дело в том, что компилятор не знает, что буфера не пересекаются, и сказать ему об этом невозможно -- в С++ пока нет необходимых выразительных средств (в С99 есть ключевое слово restrict для этого). А без этого предположения данный цикл семантически не эквивалентен memcpy.

AD>А без оптимизации — всё зависит от платформы Под intel — однозначно memcpy будет быстрее.
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Что отрабоатает быстрее?
От: Аноним  
Дата: 06.05.05 04:35
Оценка:
Здравствуйте, Antikrot, Вы писали:

A>Здравствуйте, ArtDenis, Вы писали:


AD>>А без оптимизации — всё зависит от платформы Под intel — однозначно memcpy будет быстрее.

A>Под intel — все очень просто: там оптимизированный вариант memcpy (вопрос только, будет ли оптимизированный вариант memcpy использоваться при выключенной оптимизации) использует movnt* команды — как раз чтобы избавиться от проблем с кешем, про которые упомянул MaximE. Так что да, в этом случае memcpy однозначно лучше.

Не совсем, правда, коллега. Не так давно занимался оптимизацией копирования памяти для p4-платформ.Выяснилась интересная вещь — оптимизированный memcpy (prefetch, 4xmovntq для протаскивания 32-х байт) дает выигрыш (линейно растуший до 3-х раз по скорости) лишь начиная с объема копирования 50-55 страниц. До этого рулит memcpy. Объяснить эффект довольно просто. Делаем выводы
Re[3]: Что отрабоатает быстрее?
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 06.05.05 07:07
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Здравствуйте, ArtDenis, Вы писали:


t>>> for(int i=o,i<size;i++)

t>>> dest[i]=src[i];

AD>>Есть вероятность, что оптимизатор для цикла создаст код, аналогичный коду memcpy.


Ш>Нету вероятности. Дело в том, что компилятор не знает, что буфера не пересекаются, и сказать ему об этом невозможно -- в С++ пока нет необходимых выразительных средств (в С99 есть ключевое слово restrict для этого). А без этого предположения данный цикл семантически не эквивалентен memcpy.


В данном случае это неприменимо, но оптимизация, похожая на restrict возможна: http://www.ddj.com/documents/s=880/ddj0010d/
Re[3]: Что отрабоатает быстрее?
От: ArtDenis Россия  
Дата: 06.05.05 07:22
Оценка: -1
Здравствуйте, Шахтер, Вы писали:

Ш>Нету вероятности. Дело в том, что компилятор не знает, что буфера не пересекаются, и сказать ему об этом невозможно -- в С++ пока нет необходимых выразительных средств...


Не надо путуть memmove и memcpy. memcpy по поведению аналогичен вышеприведённому циклу.
... << Rsdn@Home 1.1.4 beta 1 >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: Что отрабоатает быстрее?
От: Аноним  
Дата: 06.05.05 11:18
Оценка:
Здравствуйте, temik, Вы писали:

T> В важном учаске кода надо произвести копирование из одного буфера в другой. что отработает быстрее?

T>memcpy(dest,src,size)
T>или
T>for(int i=o,i<size;i++)
T> dest[i]=src[i];

T>буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт


если x86 платформа, то лучше всего использовать movntq — поищи топ VuDZ'a — сравнение скорости и пр.
код примерно такой (только prefetch не совсем правильно используется)

// ==================================================================
// 
// FUNCTION :  SSEmemcpy()
// 
// * Description :
//     fast copy with mmx sse - faster than memcpy in 3-4 times
// 
// * Author : [Vadim VuDZ]
// 
// * Returns : [void] - nothing
// 
// * Function parameters : 
// [to]   - pointer to destination
// [from] - pointer to source
// [sz]   - lenght of [from]
// 
// ==================================================================

void SSEmemcpy(void * to, const void * from, unsigned int sz){
                // check for correct values
                if (!to || !from || !sz) {
#ifdef  DEBUG
                                OutputDebugString("SSEmemcpy: Incorrect parameters!\n");
#endif
                                return;
                }

                // Check for SSE
                if (!_IsSSE) {
                                MMXmemcpy(to, from, sz);
                                return;
                }

                int ne32 = sz % 32;
                int szz = sz - ne32;

                if (szz != 0){
                                __asm
                                {
                                               pusha;
                                               mov esi, from;
                                               mov ecx, szz;
                                               prefetcht0 [esi + ecx - 32];                // preload first 32 bytes
                                               mov edi, to;
                                               shr ecx, 3;            // devide on 8
_l_p3:                     movq mm0, [esi + ecx * 8 - 8];      
                                               movq mm1, [esi + ecx * 8 - 16];
                                               movq mm2, [esi + ecx * 8 - 24];
                                               movq mm3, [esi + ecx * 8 - 32];
                                               prefetcht0 [esi + ecx * 8 - 64];// preload next 32 bytes
                                               movntq [edi + ecx * 8 - 8], mm0;
                                               movntq [edi + ecx * 8 - 16], mm1;
                                               movntq [edi + ecx * 8 - 24], mm2;
                                               movntq [edi + ecx * 8 - 32], mm3;
                                               sub ecx, 4;
                                               jnz _l_p3;
                                               popa;
                                }
                                __asm emms; // set fpu registers free
                }

                // check for full copy
                memcpy((char*)to + sz - (ne32), (char*)from + sz - (ne32), ne32);
}
Re[4]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 07.05.05 03:18
Оценка:
Здравствуйте, alnsn, Вы писали:

A>Здравствуйте, Шахтер, Вы писали:


Ш>>Здравствуйте, ArtDenis, Вы писали:


t>>>> for(int i=o,i<size;i++)

t>>>> dest[i]=src[i];

AD>>>Есть вероятность, что оптимизатор для цикла создаст код, аналогичный коду memcpy.


Ш>>Нету вероятности. Дело в том, что компилятор не знает, что буфера не пересекаются, и сказать ему об этом невозможно -- в С++ пока нет необходимых выразительных средств (в С99 есть ключевое слово restrict для этого). А без этого предположения данный цикл семантически не эквивалентен memcpy.


A>В данном случае это неприменимо, но оптимизация, похожая на restrict возможна: http://www.ddj.com/documents/s=880/ddj0010d/


Я извиняюсь, но не надо, пожалуйста, приводить ссылки, которые нельзя прочитать без регистрации и.т.п. фигни. Я их не читаю и подобные сайты сразу заношу в черный список.
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 07.05.05 03:18
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, Шахтер, Вы писали:


Ш>>Нету вероятности. Дело в том, что компилятор не знает, что буфера не пересекаются, и сказать ему об этом невозможно -- в С++ пока нет необходимых выразительных средств...


AD>Не надо путуть memmove и memcpy. memcpy по поведению аналогичен вышеприведённому циклу.


Действительно, не надо. А ещё неплохо бы подучить матчасть и узнать, что memcpy не работает для пересекающихся блоков данных -- его поведение в этом случае неопределено, поэтому он НЕ эквивалентен циклу.

7.21.2.1 The memcpy function

Synopsis

#include <string.h>

void *memcpy(void * restrict s1,
const void * restrict s2,
size_t n);

Description

The memcpy function copies n characters from the object pointed to by s2 into the
object pointed to by s1. If copying takes place between objects that overlap, the behavior
is undefined.
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[5]: Что отрабоатает быстрее?
От: ArtDenis Россия  
Дата: 07.05.05 05:41
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Действительно, не надо. А ещё неплохо бы подучить матчасть и узнать, что memcpy не работает для пересекающихся блоков данных -- его поведение в этом случае неопределено, поэтому он НЕ эквивалентен циклу.


Подойду с другой стороны. А где в этом коде

  for(int i=0,i<size;i++) dest[i]=src[i];


гарантия того, что если dest и src пересекаются, то перенос данных пройдёт корректно?

Ш>The memcpy function copies n characters from the object pointed to by s2 into the

Ш>object pointed to by s1. If copying takes place between objects that overlap, the behavior
Ш>is undefined.
И я о том же
... << Rsdn@Home 1.1.4 beta 1 >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 07.05.05 21:03
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, Шахтер, Вы писали:


Ш>>Действительно, не надо. А ещё неплохо бы подучить матчасть и узнать, что memcpy не работает для пересекающихся блоков данных -- его поведение в этом случае неопределено, поэтому он НЕ эквивалентен циклу.


AD>Подойду с другой стороны. А где в этом коде


AD>
AD>  for(int i=0,i<size;i++) dest[i]=src[i];
AD>


AD>гарантия того, что если dest и src пересекаются, то перенос данных пройдёт корректно?


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

Ш>>The memcpy function copies n characters from the object pointed to by s2 into the

Ш>>object pointed to by s1. If copying takes place between objects that overlap, the behavior
Ш>>is undefined.
AD>И я о том же
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[7]: Что отрабоатает быстрее?
От: ArtDenis Россия  
Дата: 08.05.05 06:30
Оценка:
Здравствуйте, Шахтер, Вы писали:

AD>>Подойду с другой стороны. А где в этом коде

AD>>
AD>>  for(int i=0,i<size;i++) dest[i]=src[i];
AD>>

AD>>гарантия того, что если dest и src пересекаются, то перенос данных пройдёт корректно?

Ш>Здесь не будет переноса данных, вообще говоря.

Извиняюсь за ошибку. Конечно же я имел ввиду копировние

Ш>Тем не менее, это полностью легальный код, имеющий свою, вполне определённую семантику. Ты не можешь при оптимизации заменить его на что-то, что делает неизвестно что. Компилятор не вправе строить догадки, что имел ввиду программист при написании кода.

Не вижу ни одного доказательства, чем memcpy по поведению отличается от цикла. Для меня из поведение абсолютно идентично, т.к.
1. Побайтно копирует данные из источника в приёмник
2. Не гарантирует, что данные будут корректно скопированы, если источник и приёмник пересекаются
3. Нет предположений, что данные приёмника должны синхронизироваться для доступа из разных потоков во время копирования данных

Я не вижу припятствий, почему оптимизатор не может преобразовать код цикла в код, аналогичный memcpy. По крайней мере этот пример подтвержадет мои слова (vc toolkit 2003).

Исходный код:
#include <memory.h>
#include <iostream>

const int size = 256;

// Ф-я используется для подавления оптимизации
// Без неё из кода будет вырезано всё, что не связано с volatile
char calc(const char * data)
{
  char result = 0;
  for (int i = 0; i < size; i++) result += data[i];
  return result;
}


int main(int argc, char* argv[])
{
  const char src[size] = {0};
  char dst1[size], dst2[size];
  volatile char dstv[size];
  
  for (int i = 0; i < size; i++) dst1[i] = src[i];
  
  memcpy(dst2, src, size);
  
  for (int i = 0; i < size; i++) dstv[i] = src[i];
  
  std::cout << calc(dst1)+calc(dst2) << "\n";
}


Третий случай — с volatile я привёл, чтобы показать, как оптимизатор ведет себя, когда программист конкретно указывает, что к dstv во время копировния может получить дотуп другой процесс или поток.

А вот что получается при оптимизации с ключём O2:
...
; for (int i = 0; i < size; i++) dst1[i] = src[i];
    mov    ecx, 64                    ; 00000040H
    lea    esi, DWORD PTR _src$[esp+1040]
    lea    edi, DWORD PTR _dst1$[esp+1040]
    rep movsd
; memcpy(dst2, src, size);
    mov    ecx, 64                    ; 00000040H
    lea    esi, DWORD PTR _src$[esp+1040]
    lea    edi, DWORD PTR _dst2$[esp+1040]
    rep movsd
; for (int i = 0; i < size; i++) dstv[i] = src[i];
    xor    eax, eax
    npad    13
$L8472:
    mov    cl, BYTE PTR _src$[esp+eax+1040]
    mov    BYTE PTR _dstv$[esp+eax+1040], cl
    inc    eax
    cmp    eax, 256                ; 00000100H
    jl    SHORT $L8472
...


строки
for (int i = 0; i < size; i++) dst1[i] = src[i];

и
memcpy(dst2, src, size);

обрабатываются аналогично.

А строка
for (int i = 0; i < size; i++) dstv[i] = src[i];

не оптимизируется потому, что компилятору явно указали, что к dstv во время копирования может получить доступ ещё один поток или процесс. Если бы компилятор оптимизировал эту строчку аналогично предыдущим, то это бы не давало возможности программисту вставить код для синхронизации содержимого dstv из разных потоков.
... << Rsdn@Home 1.1.4 beta 1 >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[5]: Что отрабоатает быстрее?
От: alnsn Великобритания http://nasonov.blogspot.com
Дата: 08.05.05 10:15
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Я извиняюсь, но не надо, пожалуйста, приводить ссылки, которые нельзя прочитать без регистрации и.т.п. фигни. Я их не читаю и подобные сайты сразу заношу в черный список.


Когда я ее читал, она была бесплатная и без регистрации. Сейчас поискал, нету такой ссылки. Но мне показалось, что можно бесплатно зарегистрироваться на 6 месяцев и почитать.
Re[8]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 08.05.05 22:23
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, Шахтер, Вы писали:


AD>>>Подойду с другой стороны. А где в этом коде

AD>>>
AD>>>  for(int i=0,i<size;i++) dest[i]=src[i];
AD>>>

AD>>>гарантия того, что если dest и src пересекаются, то перенос данных пройдёт корректно?

Ш>>Здесь не будет переноса данных, вообще говоря.

AD>Извиняюсь за ошибку. Конечно же я имел ввиду копировние

Ш>>Тем не менее, это полностью легальный код, имеющий свою, вполне определённую семантику. Ты не можешь при оптимизации заменить его на что-то, что делает неизвестно что. Компилятор не вправе строить догадки, что имел ввиду программист при написании кода.

AD>Не вижу ни одного доказательства, чем memcpy по поведению отличается от цикла.

Отличается тем, что его (memcpy) поведение не определено. В отличие от цикла.

AD>Для меня из поведение абсолютно идентично, т.к.

AD>1. Побайтно копирует данные из источника в приёмник

Нет. Цикл выполнит последовательность присваиваний

dst[0] = src[0] ;
dst[1] = src[1] ;
dst[2] = src[2] ;
dst[3] = src[3] ;
...
dst[size-1] = src[size-1] ;


Что сделает memcpy -- всё что угодно, вплоть до форматирования винчестера.

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

AD>2. Не гарантирует, что данные будут корректно скопированы, если источник и приёмник пересекаются


Это утверждение нерелевантно. А кто сказал, что цикл должен копировать данные? Цикл делает ровно то, что он делает (см. выше). Совпадает это с ожиданиями программиста или нет -- это вопрос к программисту. Компилятор не обладает телепатическими способностями.

AD>Я не вижу припятствий, почему оптимизатор не может преобразовать код цикла в код, аналогичный memcpy. По крайней мере этот пример подтвержадет мои слова (vc toolkit 2003).


Нет. Этот пример подотверждает только то, что в VC хороший оптимизатор. Он смог прочухать в данном случае, что источник и приёмник данных не пересекаются (поскольку они известны в компил-тайм) и сделал соответствующую оптимизацию.

Вот адекватный пример, демонстрирующий разницу.

/* main.cpp */ 

#include <iostream>

using namespace std;

/* main() */ 

int main()
 {
  char mem[10]={'a','b'};
  
  char *dst=mem+2;
  const char *src=mem;
  size_t size=8;

#if 1
  
  for(size_t i=0; i<size ;i++) dst[i]=src[i]; // печатает ababababab
  
#else

  memcpy(dst,src,size); //  у меня печатает abab, у тебя может форматнуть винчестер

#endif  
  
  cout.write(mem,10) << endl ;
  
  return 0;
 }
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[9]: Что отрабоатает быстрее?
От: ArtDenis Россия  
Дата: 09.05.05 09:41
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>...Нет. Цикл выполнит последовательность присваиваний

Ш>
Ш>dst[0] = src[0] ;
Ш>dst[1] = src[1] ;
Ш>dst[2] = src[2] ;
Ш>dst[3] = src[3] ;
Ш>...
Ш>dst[size-1] = src[size-1] ;
Ш>

Ш>Что сделает memcpy -- всё что угодно, вплоть до форматирования винчестера. ...

С этим я, пожалуй, соглашусь
Но с другой стороны: vc оптимизирует цикл и memcpy в одинаковый код...
... << Rsdn@Home 1.1.4 beta 1 >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[10]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 11.05.05 00:36
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, Шахтер, Вы писали:


Ш>>...Нет. Цикл выполнит последовательность присваиваний

Ш>>
Ш>>dst[0] = src[0] ;
Ш>>dst[1] = src[1] ;
Ш>>dst[2] = src[2] ;
Ш>>dst[3] = src[3] ;
Ш>>...
Ш>>dst[size-1] = src[size-1] ;
Ш>>

Ш>>Что сделает memcpy -- всё что угодно, вплоть до форматирования винчестера. ...

AD>С этим я, пожалуй, соглашусь

AD>Но с другой стороны: vc оптимизирует цикл и memcpy в одинаковый код...

Разве?

; 11   :   char mem[10]={'a','b'};

    mov    al, 97                    ; 00000061H
    push    esi
    xor    edx, edx
    mov    DWORD PTR _mem$[esp+18], edx
    mov    cl, 98                    ; 00000062H
    mov    DWORD PTR _mem$[esp+22], edx
    push    edi
    mov    BYTE PTR _mem$[esp+20], al

; 12   :   
; 13   :   char *dst=mem+2;
; 14   :   const char *src=mem;
; 15   :   size_t size=8;
; 16   : 
; 17   : #if 1
; 18   :   
; 19   :   for(size_t i=0; i<size ;i++) dst[i]=src[i];

    mov    BYTE PTR _mem$[esp+22], al
    mov    BYTE PTR _mem$[esp+24], al
    mov    BYTE PTR _mem$[esp+26], al
    mov    BYTE PTR _mem$[esp+28], al

; 20   :   
; 21   : #else
; 22   : 
; 23   :   memcpy(dst,src,size);
; 24   : 
; 25   : #endif  
; 26   :   
; 27   :   cout.write(mem,10) << endl ;

    push    10                    ; 0000000aH
    lea    eax, DWORD PTR _mem$[esp+24]
    mov    BYTE PTR _mem$[esp+25], cl
    mov    BYTE PTR _mem$[esp+27], cl
    mov    BYTE PTR _mem$[esp+29], cl
    mov    BYTE PTR _mem$[esp+31], cl
    mov    BYTE PTR _mem$[esp+33], cl


; 11   :   char mem[10]={'a','b'};

    xor    eax, eax
    mov    DWORD PTR _mem$[esp+14], eax
    push    esi
    mov    BYTE PTR _mem$[esp+16], 97        ; 00000061H
    mov    BYTE PTR _mem$[esp+17], 98        ; 00000062H

; 12   :   
; 13   :   char *dst=mem+2;
; 14   :   const char *src=mem;
; 15   :   size_t size=8;
; 16   : 
; 17   : #if 0
; 18   :   
; 19   :   for(size_t i=0; i<size ;i++) dst[i]=src[i];
; 20   :   
; 21   : #else
; 22   : 
; 23   :   memcpy(dst,src,size);

    mov    ecx, DWORD PTR _mem$[esp+16]
    mov    DWORD PTR _mem$[esp+22], eax
    mov    DWORD PTR _mem$[esp+18], ecx
    mov    edx, DWORD PTR _mem$[esp+20]

; 24   : 
; 25   : #endif  
; 26   :   
; 27   :   cout.write(mem,10) << endl ;

    push    10                    ; 0000000aH
    lea    eax, DWORD PTR _mem$[esp+20]
    push    eax
    mov    ecx, OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
    mov    DWORD PTR _mem$[esp+30], edx
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[11]: Что отрабоатает быстрее?
От: _Семен Россия www.gamedeff.com
Дата: 11.05.05 07:12
Оценка:
afair, IntelC в каждом случае вставляет практически одинаковый код на SSE с non-temporary write для достаточно больших размеров массива, который выигрывает у "классического" memcpy раза в два.
Re[11]: Что отрабоатает быстрее?
От: ArtDenis Россия  
Дата: 12.05.05 02:40
Оценка:
Здравствуйте, Шахтер, Вы писали:

AD>>Но с другой стороны: vc оптимизирует цикл и memcpy в одинаковый код...

Ш>Разве?

Имелись ввиду большие объёмы копируемых данных
... << Rsdn@Home 1.1.4 beta 1 >>
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[12]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 12.05.05 02:51
Оценка:
Здравствуйте, _Семен, Вы писали:

_С>afair, IntelC в каждом случае вставляет практически одинаковый код на SSE с non-temporary write для достаточно больших размеров массива, который выигрывает у "классического" memcpy раза в два.


Что значит, в каждом случае?
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[12]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 12.05.05 02:59
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, Шахтер, Вы писали:


AD>>>Но с другой стороны: vc оптимизирует цикл и memcpy в одинаковый код...

Ш>>Разве?

AD>Имелись ввиду большие объёмы копируемых данных


Ты знаешь, у меня такое ощущения, что то ли ты меня не понимаешь, то ли я тебя.
Ладно, информацию для размышления я выдал, остальное от меня не зависит.
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[13]: Что отрабоатает быстрее?
От: Аноним  
Дата: 12.05.05 03:02
Оценка:
Здравствуйте, Шахтер, Вы писали:

_С>>afair, IntelC в каждом случае вставляет практически одинаковый код на SSE с non-temporary write для достаточно больших размеров массива, который выигрывает у "классического" memcpy раза в два.


Ш>Что значит, в каждом случае?


Значит, и в случае использования memcpy, и если написать цикл руками.
Re[14]: Что отрабоатает быстрее?
От: Шахтер Интернет  
Дата: 12.05.05 03:28
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, Шахтер, Вы писали:


_С>>>afair, IntelC в каждом случае вставляет практически одинаковый код на SSE с non-temporary write для достаточно больших размеров массива, который выигрывает у "классического" memcpy раза в два.


Ш>>Что значит, в каждом случае?


А>Значит, и в случае использования memcpy, и если написать цикл руками.


Прочитай всю ветку с начала.
... << RSDN@Home 1.1.3 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Что отрабоатает быстрее?
От: arcman Россия  
Дата: 19.08.05 09:41
Оценка:
Здравствуйте, temik, Вы писали:

T> В важном учаске кода надо произвести копирование из одного буфера в другой. что отработает быстрее?

T>memcpy(dest,src,size)
T>или
T>for(int i=o,i<size;i++)
T> dest[i]=src[i];

T>буферы хранят данные типа BYTE. Размер буферов порядка 10-15 мегабайт


Быстрее будет копирование в цикле по 4ре байта за раз (двойными словами)
Остальные грабли разобраны в книге:
"Крис Касперски — Техника оптимизации программ. Эффективное использование памяти" http://findbook.ru/search/d0?s=1&amp;pvalue=%D2%E5%F5%ED%E8%EA%E0+%EE%EF%F2%E8%EC%E8%E7%E0%F6%E8%E8+%EF%F0%EE%E3%F0%E0%EC%EC&amp;r=0&amp;ptype=1)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.