Programowanie (PHP, Java...), Sprzęt, System (GNU, BSD, Windows...), Techblog

MMX i SSE - czy przyspieszają kopiowanie/wypełnianie

14 lutego, 2009 o 14:22:32 Dodaj komentarz Poziom: 0 Permalink

Jakiś czas temu widziałem pokazy jak przyspieszyć kopiowanie za pomocą MMX i SSE. Postanowiłem sprawdzić jak to jest. Wyniki często były zaskakujące ale wydaje mi się, że udało mi się powtórzyć je 'za każdym razem'.

Środowisko testowe: Linux notebook 2.6.29-rc3-zen1 #2 Mon Feb 9 02:27:19 CET 2009 i686 Intel(R) Celeron(R) M processor 1.50GHz GenuineIntel GNU/Linux

Ponieważ w komentarzach wykazano błędy w implementacji to poprawiłem kod.

Każdy test był wykonany na kilka sposobów:

  • Standard - czyli używając memset/memcpy
  • MMX - używanie MMX dopóki można. Potem standard.
  • MMX[short] - używanie MMX do kopiowania po 64 bajty. Potem standard
  • SSE - używanie SSE dopóki można. Potem MMX.
  • SSE[short] - używanie SSE do kopiowania po 128 bajty. Potem MMX[short].
  • SSE[unaligned] - używanie SSE dopóki można - używając ładowania niewyrównanego
  • SSE[short,unaligned] - Połączenie SSE[short] i SSE[unaligned]

Dodatkowo przy wyrównanych testach było:

  • SSE[aligned] - używanie SSE zakładając że dane są wyrównane.
  • SSE[short, aligned] - Połączenie SSE[short] i SSE[aligned].

Testy były właściwie 2 rodzajów - danych wyrównanych i niewyrównanych i o znanych z góry wielkości i nieznanej z góry wielkości.

Czasy w sekundach
Wbudowane MMX SSE
Długie Krótkie Długie Krótkie Wyrównane Krótkie wyrównane Niewyrównane Krótkie niewyrównane
Wbudowane MMX SSE
Długie Krótkie Długie Krótkie Wyrównane Krótkie wyrównane Niewyrównane Krótkie niewyrównane
Kopiowanie
Znana z góry wielkość
Wyrównane 0.982868 0.731364 0.719066 0.807502 0.739095 0.782278 0.764494 0.933182 0.948767
Niewyrównane (przesunięcie o 8) 0.979686 1.01425 1.1122 0.946973 0.702722 n/d n/d 0.80557 0.929962
Niewyrównane (przesunięcie o 4) 0.823551 0.738669 0.708918 0.731075 0.733556 n/d n/d 0.73805 0.800482
Niewyrównane (przesunięcie o 2) 0.738978 0.998168 0.940978 0.798177 0.93304 n/d n/d 0.790681 0.762154
Niewyrównane (przesunięcie o 1) 1.38732 0.781128 1.16563 1.54279 0.752582 n/d n/d 0.871613 0.791898
Nieznana z góry wielkość
Wyrównane 0.814131 0.762991 0.92082 0.737645 0.698797 0.744144 0.712088 0.74202 0.798536
Niewyrównane (przesunięcie o 8) 1.13483 0.83259 1.0434 0.695409 0.850881 n/d n/d 0.862332 0.745039
Niewyrównane (przesunięcie o 4) 0.77926 0.794189 0.785503 0.822742 1.07177 n/d n/d 0.72209 0.784494
Niewyrównane (przesunięcie o 2) 0.712837 0.829242 0.972949 0.766103 0.882174 n/d n/d 0.88227 0.722228
Niewyrównane (przesunięcie o 1) 0.743727 0.848918 0.883418 0.794465 0.730376 n/d n/d 0.784203 0.853663
Wypełnianie
Znana z góry wielkość
Wyrównane 0.81081 0.65383 0.695042 0.855161 0.716092 0.726456 0.705059 0.648848 0.736384
Niewyrównane (przesunięcie o 8) 0.737244 0.732685 0.652219 0.701332 0.81582 n/d n/d 1.05039 0.674414
Niewyrównane (przesunięcie o 4) 0.968734 0.77509 0.863252 0.764084 0.868892 n/d n/d 0.719646 0.923218
Niewyrównane (przesunięcie o 2) 0.723528 0.719882 1.06998 0.847719 0.765243 n/d n/d 0.825378 0.824253
Niewyrównane (przesunięcie o 1) 0.71951 0.729501 0.722602 0.759707 0.609097 n/d n/d 0.773491 0.97046
Nieznana z góry wielkość
Wyrównane 0.89549 0.752535 0.697823 0.713467 0.850536 0.804573 0.893425 0.702687 0.706982
Niewyrównane (przesunięcie o 8) 0.62052 0.694168 0.840253 0.643335 0.821434 n/d n/d 0.861319 0.788475
Niewyrównane (przesunięcie o 4) 0.747126 1.18094 0.669894 0.768852 0.849558 n/d n/d 0.965763 0.910739
Niewyrównane (przesunięcie o 2) 0.648971 0.789163 0.639099 0.756582 0.699075 n/d n/d 0.743467 0.71075
Niewyrównane (przesunięcie o 1) 0.655918 0.70555 0.70698 0.764856 0.772432 n/d n/d 0.720736 0.696853

Albo jako przyspieszenie:

Przyspieszenie w stosunku do wbudowanej medtody:
MMX SSE
Długie Krótkie Długie Krótkie Wyrównane Krótkie wyrównane Niewyrównane Krótkie niewyrównane
MMX SSE
Długie Krótkie Długie Krótkie Wyrównane Krótkie wyrównane Niewyrównane Krótkie niewyrównane
Kopiowanie
Znana z góry wielkość
Wyrównane 25.5888 % 26.84 % 17.8423 % 24.8022 % 20.4086 % 22.218 % 5.05521 % 3.46954 %
Niewyrównane (przesunięcie o 8) -3.52776 % -13.5257 % 3.33913 % 28.2707 % n/d n/d 17.7726 % 5.0755 %
Niewyrównane (przesunięcie o 4) 10.3068 % 13.9194 % 11.2289 % 10.9277 % n/d n/d 10.382 % 2.80116 %
Niewyrównane (przesunięcie o 2) -35.0741 % -27.335 % -8.01093 % -26.2609 % n/d n/d -6.99655 % -3.13622 %
Niewyrównane (przesunięcie o 1) 43.6953 % 15.98 % -11.2063 % 45.753 % n/d n/d 37.1731 % 42.919 %
Nieznana z góry wielkość
Wyrównane 6.28154 % -13.1046 % 9.3948 % 14.1665 % 8.59653 % 12.534 % 8.85742 % 1.91554 %
Niewyrównane (przesunięcie o 8) 26.633 % 8.0569 % 38.7213 % 25.0212 % n/d n/d 24.0122 % 34.3479 %
Niewyrównane (przesunięcie o 4) -1.91579 % -0.801145 % -5.57991 % -37.5374 % n/d n/d 7.33645 % -0.671663 %
Niewyrównane (przesunięcie o 2) -16.3298 % -36.4897 % -7.4724 % -23.7554 % n/d n/d -23.7688 % -1.31741 %
Niewyrównane (przesunięcie o 1) -14.1438 % -18.7826 % -6.82213 % 1.79515 % n/d n/d -5.44232 % -14.7818 %
Wypełnianie
Znana z góry wielkość
Wyrównane 19.3609 % 14.2781 % -5.46996 % 11.6819 % 10.4037 % 13.0426 % 19.9753 % 9.17922 %
Niewyrównane (przesunięcie o 8) 0.618384 % 11.5328 % 4.87111 % -10.6581 % n/d n/d -42.4751 % 8.52228 %
Niewyrównane (przesunięcie o 4) 19.9894 % 10.8886 % 21.1255 % 10.3064 % n/d n/d 25.7127 % 4.6985 %
Niewyrównane (przesunięcie o 2) 0.50392 % -47.8834 % -17.1646 % -5.7655 % n/d n/d -14.0769 % -13.9214 %
Niewyrównane (przesunięcie o 1) -1.38858 % -0.429737 % -5.58672 % 15.3456 % n/d n/d -7.50247 % -34.8779 %
Nieznana z góry wielkość
Wyrównane 15.9639 % 22.0736 % 20.3266 % 5.02004 % 10.1528 % 0.2306 % 21.5304 % 21.0508 %
Niewyrównane (przesunięcie o 8) -11.8688 % -35.4111 % -3.67675 % -32.3783 % n/d n/d -38.806 % -27.0668 %
Niewyrównane (przesunięcie o 4) -58.0641 % 10.3372 % -2.90794 % -13.7101 % n/d n/d -29.2637 % -21.899 %
Niewyrównane (przesunięcie o 2) -21.6022 % 1.52118 % -16.5818 % -7.72053 % n/d n/d -14.5609 % -9.51953 %
Niewyrównane (przesunięcie o 1) -7.5668 % -7.78481 % -16.6085 % -17.7635 % n/d n/d -9.88203 % -6.24087 %

Hmm. Wydaje się, że dla 'wyrównanego' kopiowania jest to dosyć dobra metoda. Ale chętnie zobaczę jak to wygląda na Core 2 czy P4.

Kod wydaje się nie funkcjonować z -fomit-frame-pointer albo tą flagą połączoną z innymi opcjami (gcc próbuje używać rejestrów SSE?):

  1. #include <cstring>
  2. #include <iostream>
  3. #include <sys/time.h>
  4. #include <cstdlib>
  5.  
  6. class standard
  7. {
  8. public:
  9.   static inline void
  10.   copy(void *dst, const void *src, size_t size) throw()
  11.   {
  12.     memcpy(dst, src, size);
  13.   }
  14.   static inline void
  15.   fill(void *dst, char byte, size_t size) throw()
  16.   {
  17.     memset(dst, byte, size);
  18.   }
  19. };
  20.  
  21. union addr {
  22.   void *ptr;
  23.   unsigned int addr;
  24. };
  25.  
  26. template<bool aligned = false, bool finish_with_self = true>
  27. class mmx
  28. {
  29. public:
  30.   static inline void
  31.   copy(void *dst, const void *src, size_t size) throw()
  32.   {
  33.     __asm__ __volatile__("\n"
  34.                          "\tmov %2, %%eax\n"
  35.                          "\tand $0xffffffc0,  %%eax\n"
  36.                          "\tand $0x0000003f,  %2\n"
  37.                          "\ttest %%eax, %%eax\n"
  38.                          "\tjz 2f\n"
  39.                          "\tmov %0, %%esi\n"
  40.                          "\tmov %1, %%edi\n"
  41.                          "\tadd %%eax, %%esi\n"
  42.                          "\tadd %%eax, %%edi\n"
  43.                          "1:\n"
  44.                          "\tmovq   (%0),  %%mm0\n"
  45.                          "\tmovq  8(%0),  %%mm1\n"
  46.                          "\tmovq 16(%0),  %%mm2\n"
  47.                          "\tmovq 24(%0),  %%mm3\n"
  48.                          "\tmovq 32(%0),  %%mm4\n"
  49.                          "\tmovq 40(%0),  %%mm5\n"
  50.                          "\tmovq 48(%0),  %%mm6\n"
  51.                          "\tmovq 56(%0),  %%mm7\n"
  52.                          "\tmovq  %%mm0,   (%1)\n"
  53.                          "\tmovq  %%mm1,  8(%1)\n"
  54.                          "\tmovq  %%mm2, 16(%1)\n"
  55.                          "\tmovq  %%mm3, 24(%1)\n"
  56.                          "\tmovq  %%mm4, 32(%1)\n"
  57.                          "\tmovq  %%mm5, 40(%1)\n"
  58.                          "\tmovq  %%mm6, 48(%1)\n"
  59.                          "\tmovq  %%mm7, 56(%1)\n"
  60.                          "\taddl    $64,     %0\n"
  61.                          "\taddl    $64,     %1\n"
  62.                          "\tcmp      %0, %%esi\n"
  63.                          "\tjne    1b\n"    
  64.                          "2:"
  65.                          : "=r"(src), "=r"(dst), "=r"(size)
  66.                          : "0"(src), "1"(dst), "2"(size)
  67.                          : "%eax", "%esi", "%edi", "memory");
  68.     if(!aligned)
  69.       {
  70.         if(finish_with_self)
  71.           {
  72.             __asm__ __volatile__("\n"
  73.                                  "\tmov %2, %%eax\n"
  74.                                  "\tand $0xfffffff8,  %%eax\n"
  75.                                  "\tand $0x00000007,  %2\n"
  76.                                  "\ttest %%eax, %%eax\n"
  77.                                  "\tjz 2f\n"
  78.                                  "\tmov %0, %%esi\n"
  79.                                  "\tmov %1, %%edi\n"
  80.                                  "\tadd %%eax, %%esi\n"
  81.                                  "\tadd %%eax, %%edi\n"
  82.                                  "1:\n"
  83.                                  "\tmovq   (%0),  %%mm0\n"
  84.                                  "\tmovq  %%mm0,   (%1)\n"
  85.                                  "\taddl     $8,     %0\n"
  86.                                  "\taddl     $8,     %1\n"
  87.                                  "\tcmp %0, %%esi\n"
  88.                                  "\tjnz 1b\n"
  89.                                  "2:"
  90.                                  : "=r"(src), "=r"(dst), "=r"(size)
  91.                                  : "0"(src), "1"(dst), "2"(size)
  92.                                  : "%eax", "%esi", "%edi", "memory");
  93.           }
  94.         standard::copy(dst, src, size);
  95.       }
  96.   }
  97.   static inline void
  98.   fill(void *dst, char byte, size_t size) throw()
  99.   {
  100.     __asm__ __volatile__ ("\n"
  101.                           "\t.byte 0x0f, 0x6e, 0xc0\n"
  102.                           /* "\tmovd %1, %%mm0\n" */
  103.                           "\tpunpcklbw %%mm0, %%mm0\n"
  104.                           "\t.byte 0x0f, 0x61, 0xc0\n"
  105.                           /* "\tpunpcklwd %%mm0, %%mm0\n" */
  106.                           "\t.byte 0x0f, 0x62, 0xc0\n"
  107.                           /* "\tpunpckldq %%mm0, %%mm0\n" */
  108.                           "\tmov %2, %%esi\n"
  109.                           "\tand $0xffffffc0,  %%esi\n"
  110.                           "\tand $0x0000003f,  %2\n"
  111.                           "\ttest %%esi, %%esi\n"
  112.                           "\tjz 2f\n"
  113.                           "\tmov %0, %%edi\n"
  114.                           "\tadd %%esi, %%edi\n"
  115.                           "\tmovq %%mm0, %%mm1\n"
  116.                           "\tmovq %%mm0, %%mm2\n"
  117.                           "\tmovq %%mm1, %%mm3\n"
  118.                           "\tmovq %%mm2, %%mm4\n"
  119.                           "\tmovq %%mm3, %%mm5\n"
  120.                           "\tmovq %%mm4, %%mm6\n"
  121.                           "\tmovq %%mm5, %%mm7\n"
  122.                           "1:\n"
  123.                           "\tmovq %%mm0,   (%0)\n"
  124.                           "\tmovq %%mm1,  8(%0)\n"
  125.                           "\tmovq %%mm2, 16(%0)\n"
  126.                           "\tmovq %%mm3, 24(%0)\n"
  127.                           "\tmovq %%mm4, 32(%0)\n"
  128.                           "\tmovq %%mm5, 40(%0)\n"
  129.                           "\tmovq %%mm6, 48(%0)\n"
  130.                           "\tmovq %%mm7, 56(%0)\n"
  131.                           "\taddl $64, %0\n"
  132.                           "\tcmpl %0, %%edi\n"
  133.                           "\tjne 1b\n"
  134.                           "2:\n"
  135.                           : "=r"(dst), "=a"(byte), "=r"(size)
  136.                           : "0"(dst), "1"(byte), "2"(size)
  137.                           : "%esi", "%edi", "memory");
  138.     if(!aligned)
  139.       {
  140.         if(finish_with_self)
  141.           {
  142.             __asm__ __volatile__ ("\n"
  143.                                   "\tmov %2, %%esi\n"
  144.                                   "\tand $0xfffffff8,  %%esi\n"
  145.                                   "\tand $0x00000007,  %2\n"
  146.                                   "\ttest %%esi, %%esi\n"
  147.                                   "\tjz 2f\n"
  148.                                   "\tmov %0, %%edi\n"
  149.                                   "\tadd %%esi, %%edi\n"
  150.                                   "1:\n"
  151.                                   "\tmovq %%mm0, (%0)\n"
  152.                                   "\tadd $8, %0\n"
  153.                                   "\tcmp %0, %%edi\n"
  154.                                   "\tjne 1b\n"
  155.                                   "2:\n"
  156.                                   : "=r"(dst), "=r"(byte), "=r"(size)
  157.                                   : "0"(dst), "1"(byte), "2"(size)
  158.                                   : "%esi", "%edi", "memory");
  159.           }
  160.         standard::fill(dst, byte, size);
  161.       }
  162.   }
  163. };
  164.  
  165. template<bool aligned = false, bool finish_with_self = true,
  166.          bool fnalign = false>
  167. class sse
  168. {
  169. public:
  170.   static inline void
  171.   copy(void *_dst, const void *_src, size_t size) throw()
  172.   {
  173.     addr dst, src;
  174.     dst.ptr = _dst;
  175.     src.ptr = const_cast<void *>(_src);
  176.     if(!fnalign)
  177.       {
  178.         if(dst.addr % 16 != src.addr % 16)
  179.           {
  180.             mmx<false, finish_with_self>::copy(dst.ptr, src.ptr, size);
  181.             return;
  182.           }
  183.         if(!aligned && dst.addr % 16)
  184.           {
  185.             mmx<false, finish_with_self>::copy(dst.ptr, src.ptr,
  186.                                                16 - (dst.addr % 0x10));
  187.             size -= 16 - dst.addr % 16;
  188.             dst.addr += 16 - dst.addr % 16;
  189.             src.addr += 16 - src.addr % 16;
  190.           }
  191.         __asm__ __volatile__ ("\n"
  192.                               "\tmov %2, %%eax\n"
  193.                               "\tand $0xffffff80,  %%eax\n"
  194.                               "\tand $0x0000007f,  %2\n"
  195.                               "\ttest %%eax, %%eax\n"
  196.                               "\tjz 2f\n"
  197.                               "\tmov %0, %%esi\n"
  198.                               "\tmov %1, %%edi\n"
  199.                               "\tadd %%eax, %%esi\n"
  200.                               "\tadd %%eax, %%edi\n"
  201.                               "1:\n"
  202.                               "\tmovaps    (%0),  %%xmm0\n"
  203.                               "\tmovaps  16(%0),  %%xmm1\n"
  204.                               "\tmovaps  32(%0),  %%xmm2\n"
  205.                               "\tmovaps  48(%0),  %%xmm3\n"
  206.                               "\tmovaps  64(%0),  %%xmm4\n"
  207.                               "\tmovaps  80(%0),  %%xmm5\n"
  208.                               "\tmovaps  96(%0),  %%xmm6\n"
  209.                               "\tmovaps 112(%0),  %%xmm7\n"
  210.                               "\tmovaps  %%xmm0,    (%1)\n"
  211.                               "\tmovaps  %%xmm1,  16(%1)\n"
  212.                               "\tmovaps  %%xmm2,  32(%1)\n"
  213.                               "\tmovaps  %%xmm3,  48(%1)\n"
  214.                               "\tmovaps  %%xmm4,  64(%1)\n"
  215.                               "\tmovaps  %%xmm5,  80(%1)\n"
  216.                               "\tmovaps  %%xmm6,  96(%1)\n"
  217.                               "\tmovaps  %%xmm7, 112(%1)\n"
  218.                               "\taddl      $128,      %0\n"
  219.                               "\taddl      $128,      %1\n"
  220.                               "\tcmp %0, %%esi\n"
  221.                               "\tjnz 1b\n"
  222.                               "2:"
  223.                               : "=r"(src), "=r"(dst), "=r"(size)
  224.                               : "0"(src), "1"(dst), "2"(size)
  225.                               : "%eax", "%esi", "%edi", "memory");
  226.         if(finish_with_self)
  227.           {
  228.             __asm__ __volatile__("\n"
  229.                                  "\tmov %2, %%eax\n"
  230.                                  "\tand $0xfffffff0,  %%eax\n"
  231.                                  "\tand $0x0000000f,  %2\n"
  232.                                  "\ttest %%eax, %%eax\n"
  233.                                  "\tjz 2f\n"
  234.                                  "\tmov %0, %%esi\n"
  235.                                  "\tmov %1, %%edi\n"
  236.                                  "\tadd %%eax, %%esi\n"
  237.                                  "\tadd %%eax, %%edi\n"
  238.                                  "1:\n"
  239.                                  "\tmovaps   (%0), %%xmm0\n"
  240.                                  "\tmovaps %%xmm0,   (%1)\n"
  241.                                  "\taddl      $16,     %0\n"
  242.                                  "\taddl      $16,     %1\n"
  243.                                  "\tcmp %0, %%esi\n"
  244.                                  "\tjnz 1b\n"
  245.                                  "2:"
  246.                                  : "=r"(src), "=r"(dst), "=r"(size)
  247.                                  : "0"(src), "1"(dst), "c"(size)
  248.                                  : "%eax", "%esi", "%edi", "memory");
  249.           }
  250.         mmx<aligned, finish_with_self>::copy(dst.ptr, src.ptr, size);
  251.       }
  252.     else
  253.       {
  254.         __asm__ __volatile__ ("\n"
  255.                               "\tmov %2, %%eax\n"
  256.                               "\tand $0xffffff80,  %%eax\n"
  257.                               "\tand $0x0000007f,  %2\n"
  258.                               "\ttest %%eax, %%eax\n"
  259.                               "\tjz 2f\n"
  260.                               "\tmov %0, %%esi\n"
  261.                               "\tmov %1, %%edi\n"
  262.                               "\tadd %%eax, %%esi\n"
  263.                               "\tadd %%eax, %%edi\n"
  264.                               "\t1:\n"
  265.                               "\tmovups    (%0),  %%xmm0\n"
  266.                               "\tmovups  16(%0),  %%xmm1\n"
  267.                               "\tmovups  32(%0),  %%xmm2\n"
  268.                               "\tmovups  48(%0),  %%xmm3\n"
  269.                               "\tmovups  64(%0),  %%xmm4\n"
  270.                               "\tmovups  80(%0),  %%xmm5\n"
  271.                               "\tmovups  96(%0),  %%xmm6\n"
  272.                               "\tmovups 112(%0),  %%xmm7\n"
  273.                               "\tmovups  %%xmm0,    (%1)\n"
  274.                               "\tmovups  %%xmm1,  16(%1)\n"
  275.                               "\tmovups  %%xmm2,  32(%1)\n"
  276.                               "\tmovups  %%xmm3,  48(%1)\n"
  277.                               "\tmovups  %%xmm4,  64(%1)\n"
  278.                               "\tmovups  %%xmm5,  80(%1)\n"
  279.                               "\tmovups  %%xmm6,  96(%1)\n"
  280.                               "\tmovups  %%xmm7, 112(%1)\n"
  281.                               "\taddl      $128,      %0\n"
  282.                               "\taddl      $128,      %1\n"
  283.                               "\tcmp %0, %%esi\n"
  284.                               "\tjnz 1b\n"
  285.                               "2:"
  286.                               : "=r"(src), "=r"(dst), "=r"(size)
  287.                               : "0"(src), "1"(dst), "2"(size)
  288.                               : "%eax", "%esi", "%edi", "memory");
  289.         if(!aligned)
  290.           {
  291.             if(finish_with_self)
  292.               {
  293.                 __asm__ __volatile__("\n"
  294.                                      "\tmov %2, %%eax\n"
  295.                                      "\tand $0xfffffff0,  %%eax\n"
  296.                                      "\tand $0x0000000f,  %2\n"
  297.                                      "\ttest %%eax, %%eax\n"
  298.                                      "\tjz 2f\n"
  299.                                      "\tmov %0, %%esi\n"
  300.                                      "\tmov %1, %%edi\n"
  301.                                      "\tadd %%eax, %%esi\n"
  302.                                      "\tadd %%eax, %%edi\n"
  303.                                      "1:\n"
  304.                                      "\tmovups   (%0), %%xmm0\n"
  305.                                      "\tmovups %%xmm0,   (%1)\n"
  306.                                      "\taddl      $16,     %0\n"
  307.                                      "\taddl      $16,     %1\n"
  308.                                      "\tcmp       %0, %%esi\n"
  309.                                      "\tjnz 1b\n"
  310.                                      "2:"
  311.                                      : "=r"(src), "=r"(dst), "=r"(size)
  312.                                      : "0"(src), "1"(dst), "2"(size)
  313.                                      : "%eax", "%esi", "%edi", "memory");
  314.               }
  315.             mmx<aligned, finish_with_self>::copy(dst.ptr, src.ptr, size);
  316.           }
  317.       }
  318.   }
  319.   static inline void
  320.   fill(void *_dst, char byte, size_t size) throw()
  321.   {
  322.     if(!fnalign)
  323.       {
  324.         addr dst;
  325.         dst.ptr = _dst;
  326.         if(dst.addr % 16)
  327.           {
  328.             mmx<aligned, finish_with_self>::fill(dst.ptr, byte,
  329.                                                  16 - dst.addr % 16);
  330.             size -= 16 - dst.addr % 16;
  331.             dst.addr += 16 - dst.addr % 16;
  332.           }
  333.         __asm__ __volatile__ ("\n"
  334.                               "\t.byte 0x66, 0x0f, 0x6e, 0xc0\n"
  335.                               /* "\tmovd %1, %%xmm0\n" */
  336.                               "\tpunpcklbw %%xmm0, %%xmm0\n"
  337.                               "\t.byte 0x66, 0x0f, 0x60, 0xc0\n"
  338.                               /* "\tpunpcklbw %%xmm0, %%xmm0\n" */
  339.                               "\t.byte 0x66, 0x0f, 0x61, 0xc0\n"
  340.                               /* "\tpunpcklwd %%xmm0, %%xmm0\n" */
  341.                               "\t.byte 0x66, 0x0f, 0x62, 0xc0\n"
  342.                               /* "\tpunpckldq %%xmm0, %%xmm0\n" */
  343.                               "\t.byte 0x0f, 0x14, 0xc0\n"
  344.                               /* "\t unpcklps %%xmm0, %%xmm0\n" */
  345.                               "\tmov %2, %%esi\n"
  346.                               "\tand $0xffffff80, %%esi\n"
  347.                               "\tand $0x0000007f, %2\n"
  348.                               "\ttest %%esi, %%esi\n"
  349.                               "\tjz 2f\n"
  350.                               "\tmov %0, %%edi\n"
  351.                               "\tadd %%esi, %%edi\n"
  352.                               "\t.byte 0x0f, 0x28, 0xc8\n"
  353.                               /* "\tmovaps %%xmm0, %%xmm1\n" */
  354.                               "\t.byte 0x0f, 0x28, 0xd0\n"
  355.                               /* "\tmovaps %%xmm0, %%xmm2\n" */
  356.                               "\t.byte 0x0f, 0x28, 0xd9\n"
  357.                               /* "\tmovaps %%xmm1, %%xmm3\n" */
  358.                               "\t.byte 0x0f, 0x28, 0xe2\n"
  359.                               /* "\tmovaps %%xmm2, %%xmm4\n" */
  360.                               "\t.byte 0x0f, 0x28, 0xeb\n"
  361.                               /* "\tmovaps %%xmm3, %%xmm5\n" */
  362.                               "\t.byte 0x0f, 0x28, 0xf4\n"
  363.                               /* "\tmovaps %%xmm4, %%xmm6\n" */
  364.                               "\t.byte 0x0f, 0x28, 0xfd\n"
  365.                               /* "\tmovaps %%xmm5, %%xmm7\n" */
  366.                               "1:\n"
  367.                               "\tmovaps %%xmm0,   (%0)\n"
  368.                               "\tmovaps %%xmm1,  16(%0)\n"
  369.                               "\tmovaps %%xmm2,  32(%0)\n"
  370.                               "\tmovaps %%xmm3,  48(%0)\n"
  371.                               "\tmovaps %%xmm4,  64(%0)\n"
  372.                               "\tmovaps %%xmm5,  80(%0)\n"
  373.                               "\tmovaps %%xmm6,  96(%0)\n"
  374.                               "\tmovaps %%xmm7, 112(%0)\n"
  375.                               "\taddl $128, %0\n"
  376.                               "\tcmp %0, %%edi\n"
  377.                               "\tjnz 1b\n"
  378.                               "2:\n"
  379.                               : "=r"(dst), "=a"(byte), "=r"(size)
  380.                               : "0"(dst), "1"(byte), "2"(size)
  381.                               : "%esi", "%edi", "memory");
  382.         if(!aligned)
  383.           {
  384.             if(finish_with_self)
  385.               {
  386.                 __asm__ __volatile__ ("\n"
  387.                                       "\tmov %2, %%esi\n"
  388.                                       "\tand $0xfffffff8, %%esi\n"
  389.                                       "\tand $0x00000007, %2\n"
  390.                                       "\ttest %%esi, %%esi\n"
  391.                                       "\tjz 2f\n"
  392.                                       "\tmov %0, %%edi\n"
  393.                                       "\tadd %%esi, %%edi\n"
  394.                                       "1:\n"
  395.                                       "\tmovaps %%xmm0, (%0)\n"
  396.                                       "\taddl $16, %0\n"
  397.                                       "\tcmp %0, %%edi\n"
  398.                                       "\tjnz 1b\n"
  399.                                       "2:\n"
  400.                                       : "=r"(dst), "=a"(byte), "=r"(size)
  401.                                       : "0"(dst), "1"(byte), "2"(size)
  402.                                       : "%esi", "%edi", "memory");
  403.               }
  404.             mmx<aligned, finish_with_self>::fill(dst.ptr, byte, size);
  405.           }
  406.       }
  407.     else
  408.       {
  409.         __asm__ __volatile__ ("\n"
  410.                               "\t.byte 0x66, 0x0f, 0x6e, 0xc0\n"
  411.                               /* "\tmovd %1, %%xmm0\n" */
  412.                               "\tpunpcklbw %%xmm0, %%xmm0\n"
  413.                               "\t.byte 0x66, 0x0f, 0x60, 0xc0\n"
  414.                               /* "\tpunpcklbw %%xmm0, %%xmm0\n" */
  415.                               "\t.byte 0x66, 0x0f, 0x61, 0xc0\n"
  416.                               /* "\tpunpcklwd %%xmm0, %%xmm0\n" */
  417.                               "\t.byte 0x66, 0x0f, 0x62, 0xc0\n"
  418.                               /* "\tpunpckldq %%xmm0, %%xmm0\n" */
  419.                               "\t.byte 0x0f, 0x14, 0xc0\n"
  420.                               /* "\t unpcklps %%xmm0, %%xmm0\n" */
  421.                               "\tmov %2, %%esi\n"
  422.                               "\tand $0xffffff80, %%esi\n"
  423.                               "\tand $0x0000007f, %2\n"
  424.                               "\ttest %%esi, %%esi\n"
  425.                               "\tjz 2f\n"
  426.                               "\tmov %0, %%edi\n"
  427.                               "\tadd %%esi, %%edi\n"
  428.                               "\t.byte 0x0f, 0x28, 0xc8\n"
  429.                               /* "\tmovaps %%xmm0, %%xmm1\n" */
  430.                               "\t.byte 0x0f, 0x28, 0xd0\n"
  431.                               /* "\tmovaps %%xmm0, %%xmm2\n" */
  432.                               "\t.byte 0x0f, 0x28, 0xd9\n"
  433.                               /* "\tmovaps %%xmm1, %%xmm3\n" */
  434.                               "\t.byte 0x0f, 0x28, 0xe2\n"
  435.                               /* "\tmovaps %%xmm2, %%xmm4\n" */
  436.                               "\t.byte 0x0f, 0x28, 0xeb\n"
  437.                               /* "\tmovaps %%xmm3, %%xmm5\n" */
  438.                               "\t.byte 0x0f, 0x28, 0xf4\n"
  439.                               /* "\tmovaps %%xmm4, %%xmm6\n" */
  440.                               "\t.byte 0x0f, 0x28, 0xfd\n"
  441.                               /* "\tmovaps %%xmm5, %%xmm7\n" */
  442.                               "1:\n"
  443.                               "\tmovups %%xmm0,    (%0)\n"
  444.                               "\tmovups %%xmm1,  16(%0)\n"
  445.                               "\tmovups %%xmm2,  32(%0)\n"
  446.                               "\tmovups %%xmm3,  48(%0)\n"
  447.                               "\tmovups %%xmm4,  64(%0)\n"
  448.                               "\tmovups %%xmm5,  80(%0)\n"
  449.                               "\tmovups %%xmm6,  96(%0)\n"
  450.                               "\tmovups %%xmm7, 112(%0)\n"
  451.                               "\taddl $128, %0\n"
  452.                               "\tcmp %0, %%edi\n"
  453.                               "\tjnz 1b\n"
  454.                               "2:\n"
  455.                               : "=r"(_dst), "=a"(byte), "=r"(size)
  456.                               : "0"(_dst), "1"(byte), "2"(size)
  457.                               : "%esi", "%edi", "memory");
  458.         if(!aligned)
  459.           {
  460.             if(finish_with_self)
  461.               {
  462.                 __asm__ __volatile__ ("\n"
  463.                                       "\tmov %2, %%esi\n"
  464.                                       "\tand $0xfffffff0, %%esi\n"
  465.                                       "\tand $0x0000000f, %2\n"
  466.                                       "\ttest %%esi, %%esi\n"
  467.                                       "\tjz 2f\n"
  468.                                       "\tmov %0, %%edi\n"
  469.                                       "\tadd %%esi, %%edi\n"
  470.                                       "1:\n"
  471.                                       "\tmovups %%xmm0, (%0)\n"
  472.                                       "\taddl $16, %0\n"
  473.                                       "\tcmp %0, %%edi\n"
  474.                                       "\tjnz 1b\n"
  475.                                       "2:\n"
  476.                                       : "=r"(_dst), "=r"(byte), "=r"(size)
  477.                                       : "0"(_dst), "1"(byte), "2"(size)
  478.                                       : "%eax", "%esi", "%edi", "memory");
  479.               }
  480.             mmx<aligned, finish_with_self>::fill(_dst, byte, size);
  481.           }
  482.       }
  483.   }
  484. };
  485.  
  486. const size_t clearing_chunk = 16*1024*1024;
  487. char clearing[clearing_chunk];
  488. inline void
  489. clear_cache() throw()
  490. {
  491.   for(unsigned i = 0; 0 && i < clearing_chunk; i++)
  492.     {
  493.       clearing[i] = rand();
  494.       clearing[i + clearing_chunk] ^= clearing[i];
  495.     }
  496. }
  497.  
  498. inline void
  499. clear_data(void *_data, size_t size) throw()
  500. {
  501.   union {
  502.     void *raw;
  503.     char *bytes;
  504.     int *words;
  505.   } data;
  506.   data.raw = _data;
  507.   size_t fast, slow;
  508.   fast = size / sizeof(int);
  509.   slow = size % sizeof(int);
  510.   for(size_t i = 0; i < fast; i++)
  511.     data.words[i] = rand();
  512.   for(size_t i = 0; i < slow; i++)
  513.     data.bytes[fast*sizeof(int) + i] = rand() % 256;
  514. }
  515.  
  516. const unsigned n = 16;
  517. class test
  518. {
  519.   static inline void
  520.   check_copy(void *_ptr, void *_data, size_t size, int run)
  521.   {
  522.     unsigned char *ptr = reinterpret_cast<unsigned char *>(_ptr);
  523.     unsigned char *data = reinterpret_cast<unsigned char *>(_data);
  524.     for(size_t i = 0; i < size; i++)
  525.       {
  526.         if(data[i] != ptr[i])
  527.           {
  528.             unsigned short _p = ptr[i], _d = data[i];
  529.             std::cerr << "Problem with " << i << " - "
  530.                       << std::hex << _p << " != "
  531.                       << std::hex << _d << " in run "
  532.                       << std::dec << run << std::endl;
  533.             throw i;
  534.           }
  535.       }
  536.   }
  537.   static inline void
  538.   check_fill(void *_ptr, char fill, size_t size, int run)
  539.   {
  540.     unsigned char *ptr = reinterpret_cast<unsigned char *>(_ptr);
  541.     for(int i = 0; i < size; i++)
  542.       {
  543.         if(ptr[i] != (unsigned char)fill)
  544.           {
  545.             unsigned short p = ptr[i], f = ((unsigned char)fill);
  546.             std::cerr << "Problem with " << i << " - "
  547.                       << std::hex << p << " != "
  548.                       << std::hex << f << " in run "
  549.                       << std::dec << run << std::endl;
  550.             throw i;
  551.           }
  552.       }
  553.   }
  554. public:
  555.   template<typename T>
  556.   static inline long long
  557.   copy(void *dst, void *src, size_t size)
  558.   {
  559.     timeval total;
  560.     timerclear(&total);
  561.     for(unsigned int i = 0; i < n; i++)
  562.       {
  563.         timeval start, end, diff;
  564.         clear_data(dst, size);
  565.         clear_data(src, size);
  566.         clear_cache();
  567.         gettimeofday(&start, NULL);
  568.         T::copy(dst, src, size);
  569.         gettimeofday(&end, NULL);
  570.         check_copy(dst, src, size, i);
  571.         timersub(&end, &start, &diff);
  572.         timeradd(&total, &diff, &total);
  573.       }
  574.     return total.tv_sec *1000000L + total.tv_usec;
  575.   }
  576.   template<bool aligned>
  577.   static inline void
  578.   copy(std::ostream &os, void *dst, void *src, size_t size)
  579.   {
  580.     os << "Standard: " << test::copy<standard>(dst, src, size) << "\n";
  581.     os << "MMX: " << test::copy<mmx<false, true> >(dst, src, size) << "\n";
  582.     os << "MMX[short]: " << test::copy<mmx<false, false> >(dst, src, size) << "\n";
  583.     os << "SSE: " << test::copy<sse<false, true, false> >(dst, src, size) << "\n";
  584.     os << "SSE[short]: " << test::copy<sse<false, false, false> >(dst, src, size) << "\n";
  585.     if(aligned)
  586.       {
  587.         os << "SSE[aligned]: " << test::copy<sse<true, true, false> >(dst, src, size) << "\n";
  588.         os << "SSE[short, aligned]: " << test::copy<sse<true, false, false> >(dst, src, size) << "\n";
  589.       }
  590.     os << "SSE[unaligned]: " << test::copy<sse<false, true, true> >(dst, src, size) << "\n";
  591.     os << "SSE[short, unaligned]: " << test::copy<sse<false, false, true> >(dst, src, size) << "\n";
  592.   }
  593.   template<typename T>
  594.   static inline long long
  595.   fill(void *dst, char byte, size_t size)
  596.   {
  597.     timeval total;
  598.     timerclear(&total);
  599.     for(unsigned int i = 0; i < n; i++)
  600.       {
  601.         timeval start, end, diff;
  602.         clear_data(dst, size);
  603.         clear_cache();
  604.         gettimeofday(&start, NULL);
  605.         T::fill(dst, byte, size);
  606.         gettimeofday(&end, NULL);
  607.         check_fill(dst, byte, size, i);
  608.         timersub(&end, &start, &diff);
  609.         timeradd(&total, &diff, &total);
  610.       }
  611.     return total.tv_sec *1000000L + total.tv_usec;
  612.   }
  613.   template<bool aligned>
  614.   static inline void
  615.   fill(std::ostream &os, void *dst, char byte, size_t size)
  616.   {
  617.     os << "Standard: " << test::fill<standard>(dst, byte, size) << "\n";
  618.     os << "MMX: " << test::fill<mmx<false, true> >(dst, byte, size) << "\n";
  619.     os << "MMX[short]: " << test::fill<mmx<false, false> >(dst, byte, size) << "\n";
  620.     os << "SSE: " << test::fill<sse<false, true, false> >(dst, byte, size) << "\n";
  621.     os << "SSE[short]: " << test::fill<sse<false, false, false> >(dst, byte, size) << "\n";
  622.     if(aligned)
  623.       {
  624.         os << "SSE[aligned]: " << test::fill<sse<true, true, false> >(dst, byte, size) << "\n";
  625.         os << "SSE[short, aligned]: " << test::fill<sse<true, false, false> >(dst, byte, size) << "\n";
  626.       }
  627.     os << "SSE[unaligned]: " << test::fill<sse<false, true, true> >(dst, byte, size) << "\n";
  628.     os << "SSE[short, unaligned]: " << test::fill<sse<false, false, true> >(dst, byte, size) << "\n";
  629.   }
  630. };
  631.  
  632. const size_t size = 16*1024*1024;
  633.  
  634. char test1[size] __attribute__((aligned(16)));
  635. char test2[size] __attribute__((aligned(16)));
  636.  
  637. size_t offsets[] = {8, 4, 2, 1};
  638.  
  639. int
  640. main()
  641. {
  642.   volatile char *vtest1 = const_cast<volatile char *>(test1);
  643.   volatile char *vtest2 = const_cast<volatile char *>(test2);
  644.   volatile size_t vsize = size;
  645.   volatile size_t *voffsets = const_cast<volatile size_t *>(offsets);
  646.   std::cout.sync_with_stdio(true);
  647.   std::cout << "\t\tTest static, aligment copy:\n";
  648.   test::copy<true>(std::cout, test1, test2, size);
  649.   std::cout << "\t\tTest static, unaligment copy:\n";
  650.   for(size_t *offset = offsets;
  651.       offset < &offsets[sizeof(offsets)/sizeof(offsets[0])];
  652.       offset++)
  653.     {
  654.       std::cout << "\tOffset: " << *offset << "\n";
  655.       test::copy<false>(std::cout,
  656.                         test1 + *offset, test2 + *offset, size - *offset);
  657.     }
  658.   std::cout << "\t\tTest dynamic, aligment copy:\n";
  659.   test::copy<true>(std::cout,
  660.                    const_cast<char *>(vtest1), const_cast<char *>(vtest2),
  661.                    vsize);
  662.   for(volatile size_t *voffset = voffsets;
  663.       voffset < &voffsets[sizeof(offsets)/sizeof(offsets[0])];
  664.       voffset++)
  665.     {
  666.       std::cout << "\tOffset: " << *voffset << "\n";
  667.       test::copy<false>(std::cout,
  668.                         const_cast<char *>(vtest1) + *voffset,
  669.                         const_cast<char *>(vtest2) + *voffset,
  670.                         size - *voffset);
  671.     }
  672.   std::cout << "\t\tTest static, aligment fill:\n";
  673.   test::fill<true>(std::cout, test1, 0, size);
  674.   std::cout << "\t\tTest static, unaligment fill:\n";
  675.   for(size_t *offset = offsets;
  676.       offset < &offsets[sizeof(offsets)/sizeof(offsets[0])];
  677.       offset++)
  678.     {
  679.       std::cout << "\tOffset: " << *offset << "\n";
  680.       test::fill<false>(std::cout, test1 + *offset, 0, size - *offset);
  681.     }
  682.   std::cout << "\t\tTest dynamic, aligment fill:\n";
  683.   test::fill<true>(std::cout, const_cast<char *>(vtest1), (char)rand(), vsize);
  684.   for(volatile size_t *voffset = voffsets;
  685.       voffset < &voffsets[sizeof(offsets)/sizeof(offsets[0])];
  686.       voffset++)
  687.     {
  688.       std::cout << "\tOffset: " << *voffset << "\n";
  689.       test::fill<false>(std::cout, const_cast<char *>(vtest2) + *voffset,
  690.                         (char)rand(), size - *voffset);
  691.     }
  692. }

Otagowano: , , ,

Komentarze do wpisu

Możesz śledzić odpowiedzi poprzez kanał RSS. Możesz dodać komentarz lub zostawić ślad (trackback) ze swojego bloga.

#

Uzytkownik

Hmm. Tabelka mieści się tylko jak zmniejszę czcionkę. Przepraszam.

14 lutego 2009, 14:26:51

#

sprae

A niełatwiej było użyć liboil? http://liboil.freedesktop.org/wiki/
Z resztą mój zacny kolega mIGu zwrócił uwagę na pewien aspekt. Wydajność pamięci w „Salcesonie” może być tak mała, że procesor czeka niezależnie czy jest to normalne kopiowanie, czy SSE.

14 lutego 2009, 15:02:18

#

Uzytkownik

„A niełatwiej było użyć liboil? http://liboil.freedesktop.org/wiki/”

Łatwiej ale nie ma zabawy ;)

„Z resztą mój zacny kolega mIGu zwrócił uwagę na pewien aspekt. Wydajność pamięci w „Salcesonie” może być tak mała, że procesor czeka niezależnie czy jest to normalne kopiowanie, czy SSE.”

Dlatego chciałbym powtórzyć na Core 2. Pewnie to dzisiaj zrobię.

14 lutego 2009, 15:05:58

#

Branch Predictor

W praktyce wypełnianie/kopiowanie instrukcjami nawet tylko MMX może być tak ~90% szybsze od standardowego, jedynie w Twoim kodzie poważną część zysków „kasuje” kod wejścia i wyjścia do/z nowych procedur oraz instrukcja LOOP (mogłeś ją zastąpić parą DEC/SUB + JNZ/JNS lub czymś w podobie). Pewnie sporo do powiedzenia ma także kod związany z szablonami. W programowanu na takim poziomie, nawet byle bzdura może spowodować poważne straty. Zobacz http://fastcode.sourceforge.net/ (tam poszukaj „Move Challenge” oraz „FillChar Challenge”).

14 lutego 2009, 16:18:56

#

Grzegorz

A ma to jakieś znaczenie dla kopiowania nie z pamięci do pamięci, tylko dla dysk – dysk lub dysk – pamięć? Bo z tego co widzę, to dysk – dysk, to w grę wchodzi tylko rozmiar bufora, np. Terra Copy.

Śledzenie [wł].

14 lutego 2009, 16:23:01

#

Branch Predictor

@Grzegorz: .. uhm, pomylileś blogi/wpisy?

14 lutego 2009, 16:25:03

#

Uzytkownik

Hmm. W pliku obiektowym nie ma wejścia wyjścia z procedury gdyż jest to wyoptymalizowane (zauważ słowa typu inline) – zapomniałem podać ważnej rzeczy – czyli flag (-Os -fomit-frame-pointer -mtune=pentium-m -march=pentium-m -mfpmath=sse -pipe -w -ftree-vectorize -ftree-loop-optimize -freorder-blocks-and-partition -fgcse-sm -fgcse-las -fgcse-after-reload -ftracer -maccumulate-outgoing-args -fvisibility-inlines-hidden -fno-rtti -fno-exceptions -Wl,-O1 Wl,-add-needed Wl,-as-needed Wl,-hash-style=both Wl,-sort-common [Skopiowane z /etc/make.conf więc nie wszystko ma sens]).
A LOOPa przeoczyłem :( Zaraz sprawdzę
@Grzegorz: Czy mi się wydaje czy Tam chodzi o kopiowanie plików? Tutaj chodzi o kopiowanie z pamięci do pamięci więc co najwyżej może mieć (i ma ogromne) znaczenie cache (którego niczym nie zmienisz – poza wyłączeniem)

14 lutego 2009, 16:28:16

#

Branch Predictor

Poza tym chyba masz błłąd w kodzie, w liniach 70-71: „\taddl $8, %0\n” „\taddl $8, %0\n”
nie powinno być „\taddl $8, %0\n” „\taddl $8, %1\n”
?

14 lutego 2009, 16:36:32

#

Uzytkownik

Nie – to jest składnia AT&T więc jest
mem src, dst
Więc:
addl $8, %0 - dodaj 8 do rejestru %0
zo jest równoważne w składni Intela
add eax, 8 (jeśli %0 to eax)

14 lutego 2009, 16:38:57

#

Branch Predictor

Tak, widzę, w takim razie po co dwa razy to samo, skoro możesz raz (16 zamiast 8)? I co oraz gdzie zmienia wartość %1?

14 lutego 2009, 16:41:54

#

Uzytkownik

Hmm. Poczekaj. Pisałem to lekko w nocy co nie było chyba najlepszym pomysłem ;)
Zaraz dodam optymalizacje (tak wiem – powinienembył przed dodaniem wpisu).

14 lutego 2009, 16:44:05

#

Branch Predictor

A sprawdzałeś czy to działa prawidłowo? ;-)

14 lutego 2009, 16:45:01

#

Uzytkownik

W sumie nie – prawdziwi programiści nie piszą unit testów ;)
A na poważne – poszczególne fragmenty sprawdzałem ale nie całość. Tak – wiem trochę się pospieszyłem.

14 lutego 2009, 16:46:53

#

Branch Predictor

A tak apropos, jeśli interesujesz się optymalizowaniem na takim poziomie, to polecam książkę „Programowanie – Optymalizacja Kodu: Efektywne Wykorzystanie Pamięci” Krisa Kaspersky’ego (ISBN: 83-7243-419-0). Otwiera oczy i wyjaśnia wiele niejasności.

14 lutego 2009, 16:52:56

#

Uzytkownik

Co do 70 – masz rację – myślałem że masz zamiar zmienić na Intela .

14 lutego 2009, 17:42:20

#

Branch Predictor

Tak myślałem właśnie. ;-))

14 lutego 2009, 17:43:55

#

Uzytkownik

Na razie popełniłem coś takiego – choć obawiam się że mam jakiś haisenbug (wypełnia zerami – ale w gdb wszystko jest w porządku – choć jak nacisnę c to wywala). Jakby ktoś chciał rzucić okiem to prosze.

14 lutego 2009, 20:40:32

#

zdz

A teraz pytanie za 3 punkty, czy memcpy/memset nie mają runtime detection CPU i czy same nie korzystają z SSE przy kopiowaniu? Pytam, bo tak mi się wydaje, ale w kod glibca nie chce mi się patrzeć.
I mała uwaga, wykresiki chociażby najprostsze mile widziane.

14 lutego 2009, 22:18:31

#

Uzytkownik

Nie – z tego co widzialem nie. A na pewno built-in nie ma.

14 lutego 2009, 22:19:47

#

darkjames

memcpy() zaimplementowany w SSE do kernelspace’a,

dostajemy zmmapowany entrypoint w vdso.
i wszystkie programy dostaja 100% speedupa!
(oczywiscie po rekompilacji, i zaimplementowaniu tego w libcu.)

14 lutego 2009, 22:40:02

#

Uzytkownik

W kernelspace? Nie opaca sie. Syscall to ok. 2000 cykli (nie pamitam czy w jedna czy dwie strony) – a nie dostajemy nic w zamian (bo kod w userspace i kernelspace wykonuje sie z podobna szybkoscia).

14 lutego 2009, 22:42:38

#

darkjames

nic o syscallach nie mowilem;
mowilem tylko zeby kernel wybral runtime najszybsza wersje memcpy() nawet moze robic benchmarki przy startowaniu. a potem dal procesowi dostep do niej.

14 lutego 2009, 22:55:27

Dodaj komentarz

Textile Lite włączony ( szczegółowy opis znaczników ):