LINUX.ORG.RU

Re: 32bit memset, memcpy

Правильно поставленный вопрос ето уже половина ответа ...

А по русски тоже самое спросить можешь??? может поймём а может и поможем

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

Да несовсем понятно это мягко сказано если обычные С функции то я очень бы хотел узнать как MMX ускоряет memset и memcpy :-)

x86 ★★ ()
Ответ на: Re: 32bit memset, memcpy от x86

Re: 32bit memset, memcpy

Есть 32bit массив (ARGB32).
Хотелось бы наибыйстрейшим образом его заполнить
или скопировать (BitBlitнуть).

В /usr/include/asm/string-486.h есть что-то типа этого ...

Valeriy_Onuchin ★★ ()
Ответ на: Re: 32bit memset, memcpy от x86

Re: 32bit memset, memcpy

>то я очень бы хотел узнать как MMX ускоряет memset и memcpy :-)

по сравнению с mov в цикле то ускоряет на порядок только каким боком ето нужно автору я не понимаю. Может ему нужно пересобрать libc а может подгрузить свои варианты memset и memcpy через LD_PRELOAD???

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от Valeriy_Onuchin

Re: 32bit memset, memcpy

>Хотелось бы наибыйстрейшим образом его заполнить

>или скопировать (BitBlitнуть).

тоесть тебя не устраивает быстродействие libc-шных ф-й??? думаю что сначала стоит подумать над её пересборкой с включенной оптимизацией.

или вообще рассмотреть альтернативные варианты например заполнить нулями большую область памяти можно через mmap.

ещё можешь выдрать из сорцов libc нужные тебе ф-и оптимизировать их любым известным тебе способом и перекрыть их аналоги в либс при помощи чегото типа LD_PRELOAD. Кстати оракл при установке патчит либс именно таким образом.

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

>или вообще рассмотреть альтернативные варианты например заполнить нулями большую область памяти можно через mmap.

А за счет чего mmap() будет быстрее memset()?

Dead ★★★★ ()
Ответ на: Re: 32bit memset, memcpy от Dead

Re: 32bit memset, memcpy

например потому что mmap будет обнулять страницы по мере необходимости а не в момент вызова. Тоесть есть вероятность что если к странице памяти никто не обратится то никто не будет тратить время на её обнуление.

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

> или вообще рассмотреть альтернативные варианты например
> заполнить нулями большую область памяти можно через mmap.

это верно, но это создает _новую_ область памяти.

если же нужно очистить уже существующий регион, то
можно прочитать туда /dev/zero, есть в linux такая
забавная и недокументированная возможность.

эффект будет тот же самый - страницы будут отброшены,
и page fault on demand.

idle ★★★★★ ()

Re: 32bit memset, memcpy

Как-то строка

> Нужен multiplatform 32bit memset, memcpy

противоречит сторке

> MMX-acelerated приветствуется.

BTW, icc на IA32 вместо memcpy и memset подсовывает интринсики -- уж там-то точно быстрее не получится!

Die-Hard ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

>это верно, но это создает _новую_ область памяти.

помоемому никто нам не мешает передать mmap указатель на существующую область памяти и не создавать новой. Или я не прав??

>если же нужно очистить уже существующий регион, то можно прочитать туда /dev/zero, есть в linux такая забавная и недокументированная возможность.

если ты имел ввиду чтение через mmap то я о том же только другими словами.

Кстати а можно под линуксом один сегмент физической памяти отобразить по двум разным адресам в контексте одного потока??

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

> помоемому никто нам не мешает передать mmap указатель на
> существующую область памяти и не создавать новой.

нет, MAP_FIXED не сработает, если этот адрес уже
распределен.

> если ты имел ввиду чтение через mmap то я о том же только
> другими словами.

да нет, я имел в виду имеено open("/dev/zero") + read(buf,size)

> Кстати а можно под линуксом один сегмент физической памяти
> отобразить по двум разным адресам в контексте одного потока??

хм... можно попытаться mmap("/proc/self/mem"), но сейчас
не могу сказать, выйдет ли что путное.

или я не правильно понял вопрос?

idle ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

>> помоемому никто нам не мешает передать mmap указатель на

>> существующую область памяти и не создавать новой.

>нет, MAP_FIXED не сработает, если этот адрес уже распределен.

никогда не подозревал. А можно здесь поподробней???

>> Кстати а можно под линуксом один сегмент физической памяти

>> отобразить по двум разным адресам в контексте одного потока??

>хм...

>можно попытаться mmap("/proc/self/mem"), но сейчас не могу сказать, выйдет ли что путное.

>или я не правильно понял вопрос?

поняли правильно. тоесть я подумал что если я могу дважды сделать mmap для посикс шаред мемори и получить одну память по двум разным адресам то я подумал а может можно тоже сотворить с уже распределённой памятью???

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

> > нет, MAP_FIXED не сработает, если этот адрес уже распределен.
>
> никогда не подозревал. А можно здесь поподробней???

а чего подробнее? MAP_FIXED работает только, если
в запрошенном диапазоне памяти [хaddr, adddr + size]
лежит SIGSEGV + si_code=SEGV_MAPERR, то есть этот
участок адресного пространства свободен.

idle ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

> хм... можно попытаться mmap("/proc/self/mem")

не, не выйдет, посмотрел код

idle ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

>если же нужно очистить уже существующий регион, то можно прочитать туда /dev/zero, есть в linux такая забавная и недокументированная возможность.

>эффект будет тот же самый - страницы будут отброшены, и page fault on demand.

теперь я точно ничего не понимаю

тоесть read() может освободить уже выделенную область памяти??? а как ето получается и чё из етого следует??

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

> тоесть read() может освободить уже выделенную область памяти???

да

> а как ето получается и чё из етого следует??

ну, грубо говоря, драйвер /dev/zero делает что-то вроде
munmap() + mmap(себя-любимого) с этим регионом памяти.

read() ведь вызывает соответсвующий метод драйвера (файла),
а там уже чего угодно можно сделать.

см. drivers/char/mem.c:read_zero()

idle ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

> ну, грубо говоря, 

точнее, очень-очень грубо говоря. заданный регион,
скажем, может иметь обычный файл в качестве backing
store, поэтому unmapp'а не будет, ну и так далее.

idle ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

хорошо я сделал malloc() далее ету память передал в read("/dev/zero").

так вот какая вероятность что после етого обратившись к памяти выделенной malloc() я получу SIGSEGV????

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

> так вот какая вероятность что после етого обратившись
> к памяти выделенной malloc() я получу SIGSEGV????

0 :)

idle ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от idle

Re: 32bit memset, memcpy

> так вот какая вероятность что после етого обратившись
> к памяти выделенной malloc() я получу SIGSEGV????

наверное, я плохо обьяснил. все будет работать
коорнктно после чтения из /dev/zero, просто будут
отброшены те страницы, с которыми это можно сделать.

при последующем доступе будет прозрачный для приложения
page fault, и процесс получит новую страничку с нулями.
в-общем, как после mmap(MAP_ANONYMOUS)

idle ★★★★★ ()

Re: 32bit memset, memcpy

лови memcpy из 3-го Дума. Работает не намного быстрее, чем просто memcpy, так что если 10% увеличение скорости тебя устроит, то тебе подойдёт :)

cvv:
На порядок быстрее не будет. Никогда.

На будущее
ftp://ftp.idsoftware.com/idstuff/doom3/source/win32/old/DOOM3_SDK.exe

И

http://www.gamedev.ru/forum/?group=0&topic=13358

Собственно, код:

Keiko ()
Ответ на: Re: 32bit memset, memcpy от Keiko

Re: 32bit memset, memcpy

#define EMMS_INSTRUCTION    __asm emms 

void MMX_Memcpy8B( void *dest, const void *src, const int count ) { 
  _asm { 
        mov    esi, src 
        mov    edi, dest 
        mov    ecx, count 
        shr    ecx, 3      // 8 bytes per iteration 
loop1: 
        movq  mm1,  0[ESI]  // Read in source data 
        movntq  0[EDI], mm1    // Non-temporal stores 
        add    esi, 8 
        add    edi, 8 
        dec    ecx 
        jnz    loop1 
  } 
  EMMS_INSTRUCTION 
} 
void MMX_Memcpy64B( void *dest, const void *src, const int count ) { 
  _asm { 
        mov    esi, src 
        mov    edi, dest 
        mov    ecx, count 
        shr    ecx, 6    // 64 bytes per iteration 
loop1: 
        prefetchnta 64[ESI]  // Prefetch next loop, non-temporal 
        prefetchnta 96[ESI] 
        movq mm1,  0[ESI]  // Read in source data 
        movq mm2,  8[ESI] 
        movq mm3, 16[ESI] 
        movq mm4, 24[ESI] 
        movq mm5, 32[ESI] 
        movq mm6, 40[ESI] 
        movq mm7, 48[ESI] 
        movq mm0, 56[ESI] 
        movntq  0[EDI], mm1  // Non-temporal stores 
        movntq  8[EDI], mm2 
        movntq 16[EDI], mm3 
        movntq 24[EDI], mm4 
        movntq 32[EDI], mm5 
        movntq 40[EDI], mm6 
        movntq 48[EDI], mm7 
        movntq 56[EDI], mm0 
        add    esi, 64 
        add    edi, 64 
        dec    ecx 
        jnz    loop1 
  } 
  EMMS_INSTRUCTION 
} 
void MMX_Memcpy2kB( void *dest, const void *src, const int count ) { 
  byte *tbuf = (byte *)_alloca16(2048); 
  __asm { 
    push  ebx 
        mov    esi, src 
        mov    ebx, count 
        shr    ebx, 11    // 2048 bytes at a time 
        mov    edi, dest 
loop2k: 
        push  edi      // copy 2k into temporary buffer 
        mov    edi, tbuf 
        mov    ecx, 32 
loopMemToL1: 
        prefetchnta 64[ESI] // Prefetch next loop, non-temporal 
        prefetchnta 96[ESI] 
        movq mm1,  0[ESI]  // Read in source data 
        movq mm2,  8[ESI] 
        movq mm3, 16[ESI] 
        movq mm4, 24[ESI] 
        movq mm5, 32[ESI] 
        movq mm6, 40[ESI] 
        movq mm7, 48[ESI] 
        movq mm0, 56[ESI] 
        movq  0[EDI], mm1  // Store into L1 
        movq  8[EDI], mm2 
        movq 16[EDI], mm3 
        movq 24[EDI], mm4 
        movq 32[EDI], mm5 
        movq 40[EDI], mm6 
        movq 48[EDI], mm7 
        movq 56[EDI], mm0 
        add    esi, 64 
        add    edi, 64 
        dec    ecx 
        jnz    loopMemToL1 
        pop    edi      // Now copy from L1 to system memory 
        push  esi 
        mov    esi, tbuf 
        mov    ecx, 32 
loopL1ToMem: 
        movq mm1, 0[ESI]  // Read in source data from L1 
        movq mm2, 8[ESI] 
        movq mm3, 16[ESI] 
        movq mm4, 24[ESI] 
        movq mm5, 32[ESI] 
        movq mm6, 40[ESI] 
        movq mm7, 48[ESI] 
        movq mm0, 56[ESI] 
        movntq 0[EDI], mm1  // Non-temporal stores 
        movntq 8[EDI], mm2 
        movntq 16[EDI], mm3 
        movntq 24[EDI], mm4 
        movntq 32[EDI], mm5 
        movntq 40[EDI], mm6 
        movntq 48[EDI], mm7 
        movntq 56[EDI], mm0 
        add    esi, 64 
        add    edi, 64 
        dec    ecx 
        jnz    loopL1ToMem 
        pop    esi      // Do next 2k block 
        dec    ebx 
        jnz    loop2k 
    pop    ebx 
  } 
  EMMS_INSTRUCTION 
} 
void VPCALL SIMD_MMX::Memcpy( void *dest0, const void *src0, const int count0 ) { 
  // if copying more than 16 bytes and we can copy 8 byte aligned 
  if ( count0 > 16 && !( ( (int)dest0 ^ (int)src0 ) & 7 ) ) { 
    byte *dest = (byte *)dest0; 
    byte *src = (byte *)src0; 
    // copy up to the first 8 byte aligned boundary 
    int count = ((int)dest) & 7; 
    memcpy( dest, src, count ); 
    dest += count; 
    src += count; 
    count = count0 - count; 
    // if there are multiple blocks of 2kB 
    if ( count & ~4095 ) { 
      MMX_Memcpy2kB( dest, src, count ); 
      src += (count & ~2047); 
      dest += (count & ~2047); 
      count &= 2047; 
    } 
    // if there are blocks of 64 bytes 
    if ( count & ~63 ) { 
      MMX_Memcpy64B( dest, src, count ); 
      src += (count & ~63); 
      dest += (count & ~63); 
      count &= 63; 
    } 
    // if there are blocks of 8 bytes 
    if ( count & ~7 ) { 
      MMX_Memcpy8B( dest, src, count ); 
      src += (count & ~7); 
      dest += (count & ~7); 
      count &= 7; 
    } 
    // copy any remaining bytes 
    memcpy( dest, src, count ); 
  } else { 
    // use the regular one if we cannot copy 8 byte aligned 
    memcpy( dest0, src0, count0 ); 
  } 
} 

Keiko ()
Ответ на: Re: 32bit memset, memcpy от Keiko

Re: 32bit memset, memcpy

Оптимизация mem* функций подробно описана в книге Криса Касперски "Техника оптимизации программ. Эффективное использование памяти"

Motl ()
Ответ на: Re: 32bit memset, memcpy от Keiko

Re: 32bit memset, memcpy

>cvv:На порядок быстрее не будет. Никогда.

результаты полученные мною при помощи бенчмарков на нескольких разных машинах были именно такими.

результаты исследований сделанные автором memtest86 говорят практически тоже.cvv:

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от cvv

Re: 32bit memset, memcpy

А можно твои бенчмарки посмотреть ? Они как я понимаю на C ? Скинь сюда или куда-нить на ftp, пожалуйста.

Keiko ()
Ответ на: Re: 32bit memset, memcpy от WFrag

Re: 32bit memset, memcpy

Кстати, гы-гы. В некоторых декодерах в mplayer'е можно найти код

void fast_memcpy(тра-ля-ля)
{
     memcpy(тра-ля-ля);
}

Keiko ()
Ответ на: Re: 32bit memset, memcpy от Keiko

Re: 32bit memset, memcpy

>А можно твои бенчмарки посмотреть?

возможно

>Они как я понимаю на C?

не я писал

>Скинь сюда

куда???

>или куда-нить на ftp

нет возможности

cvv ★★★★★ ()
Ответ на: Re: 32bit memset, memcpy от Keiko

Re: 32bit memset, memcpy

одна точно на асме писана а от второй только бинарники

cvv ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.