Advertisement
stgatilov

short memcpy with bit-level shift

Aug 27th, 2015
374
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.00 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <time.h>
  6. #include <tmmintrin.h>
  7.  
  8. #ifdef _MSC_VER
  9.     #define FORCEINLINE __forceinline
  10.     #define NOINLINE __declspec(noinline)
  11.     #define RESTRICT __restrict
  12. #else
  13.     #define FORCEINLINE __attribute__((always_inline)) inline
  14.     #define NOINLINE __attribute__((noinline))
  15.     #define RESTRICT __restrict__
  16. #endif
  17.  
  18. //switch to NOINLINE to see performance with forbidden inlining
  19. #define INLINING_MODE inline
  20.  
  21. INLINING_MODE void OffsetMemCpy_PaulR(uint8_t* pDest, const uint8_t* pSrc, const uint8_t srcBitOffset, const size_t size)
  22. {
  23.     if (srcBitOffset == 0)
  24.     {
  25.         for (size_t i = 0; i < size; ++i)
  26.         {
  27.             pDest[i] = pSrc[i];
  28.         }
  29.     }
  30.     else if (size > 0)
  31.     {
  32.         uint8_t v0 = pSrc[0];
  33.         for (size_t i = 0; i < size; ++i)
  34.         {
  35.             uint8_t v1 = pSrc[i + 1];
  36.             pDest[i] = (v0 >> srcBitOffset) | (v1 << (8 - srcBitOffset));
  37.             v0 = v1;
  38.         }
  39.     }
  40. }
  41.  
  42. INLINING_MODE void OffsetMemCpy_PaulR_64(uint8_t* pDest, const uint8_t* pSrc, const uint8_t srcBitOffset, size_t size)
  43. {
  44.     const uint64_t *RESTRICT source = (const uint64_t *)pSrc;
  45.     uint64_t *RESTRICT destination = (uint64_t *)pDest;
  46.     size = (size + 7) >> 3;
  47.  
  48.     if (srcBitOffset == 0)
  49.     {
  50.         for (size_t i = 0; i < size; ++i)
  51.         {
  52.             destination[i] = source[i];
  53.         }
  54.     }
  55.     else if (size > 0)
  56.     {
  57.         uint64_t v0 = source[0];
  58.         for (size_t i = 0; i < size; ++i)
  59.         {
  60.             uint64_t v1 = source[i + 1];
  61.             destination[i] = (v0 >> srcBitOffset) | (v1 << (64 - srcBitOffset));
  62.             v0 = v1;
  63.         }
  64.     }
  65. }
  66.  
  67.  
  68. INLINING_MODE void OffsetMemCpy_stgatilov(uint8_t *RESTRICT pDest, const uint8_t *RESTRICT pSrc, const uint8_t srcBitOffset, const size_t size) {
  69.     __m128i bits = (sizeof(size_t) == 8 ? _mm_cvtsi64_si128(srcBitOffset) : _mm_cvtsi32_si128(srcBitOffset));
  70.     const uint8_t *pEnd = pSrc + size;
  71.     while (pSrc < pEnd) {
  72.         __m128i input = _mm_loadu_si128((__m128i*)pSrc);
  73.         __m128i reg = _mm_shuffle_epi8(input, _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14));
  74.         __m128i shifted = _mm_srl_epi64(reg, bits);
  75.         __m128i comp = _mm_shuffle_epi8(shifted, _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, -1, -1));
  76.         _mm_storeu_si128((__m128i*)pDest, comp);
  77.         pSrc += 14;  pDest += 14;
  78.     }
  79. }
  80.  
  81.  
  82. const int ARRAYSIZE = 1<<16;
  83. const int MAXBLOCKSIZE = 64;
  84. const int QUERYCNT = 1<<12;
  85. const int LAUNCHES = 1<<26;
  86.  
  87. uint8_t input[ARRAYSIZE];
  88. uint8_t output[3][MAXBLOCKSIZE * 2];
  89. uint8_t offsets[QUERYCNT], starts[QUERYCNT];
  90.  
  91. int main() {
  92.     for (int i = 0; i < ARRAYSIZE; i++)
  93.         input[i] = rand() & 255;
  94.  
  95.     for (int i = 0; i < 1000000; i++) {
  96.         int st = rand() % (ARRAYSIZE/2);
  97.         int len = 1 + rand() % MAXBLOCKSIZE;
  98.         int offs = rand() % 8;
  99.         memset(&output[0][0], 0, sizeof(output));
  100.         OffsetMemCpy_PaulR(output[0], input + st, offs, len);
  101.         OffsetMemCpy_PaulR_64(output[1], input + st, offs, len);
  102.         OffsetMemCpy_stgatilov(output[2], input + st, offs, len);
  103.         if (memcmp(output[0], output[1], len) != 0 || memcmp(output[0], output[2], len) != 0) {
  104.             printf("Error:\n");
  105.             printf("len = %d, offset = %d\n", len, offs);
  106.             for (int q = 0; q < 4; q++) {
  107.                 for (int i = 0; i < len + (q==0); i++) {
  108.                     for (int j = 0; j < 8; j++)
  109.                         printf("%d", ((q==0 ? input + st : output[q-1])[i] >> j) & 1);
  110.                     printf(" ");
  111.                 }
  112.                 printf("\n");
  113.             }
  114.         }
  115.     }
  116.  
  117.     for (int i = 0; i < QUERYCNT; i++) {
  118.         offsets[i] = rand() % 8;
  119.         starts[i] = rand() % (ARRAYSIZE/2);
  120.     }
  121.  
  122.     printf("(billions of calls per second)\n");
  123.     for (int size = 1; size <= 32; size++) {
  124.         printf("size = %d:\n", size);
  125.  
  126.         int start = clock();
  127.         for (int i = 0; i < LAUNCHES; i++) {
  128.             int q = i & (QUERYCNT-1);
  129.             OffsetMemCpy_PaulR(output[0], input + starts[q], offsets[q], size);
  130.         }
  131.         printf("  %0.3g  (Paul R)\n", 1e-9 * LAUNCHES / (double(clock() - start) / CLOCKS_PER_SEC));
  132.  
  133.         start = clock();
  134.         for (int i = 0; i < LAUNCHES; i++) {
  135.             int q = i & (QUERYCNT-1);
  136.             OffsetMemCpy_PaulR_64(output[0], input + starts[q], offsets[q], size);
  137.         }
  138.         printf("  %0.3g  (Paul R x64)\n", 1e-9 * LAUNCHES / (double(clock() - start) / CLOCKS_PER_SEC));
  139.  
  140.         start = clock();
  141.         for (int i = 0; i < LAUNCHES; i++) {
  142.             int q = i & (QUERYCNT-1);
  143.             OffsetMemCpy_stgatilov(output[0], input + starts[q], offsets[q], size);
  144.         }
  145.         printf("  %0.3g  (stgatilov)\n", 1e-9 * LAUNCHES / (double(clock() - start) / CLOCKS_PER_SEC));
  146.     }
  147.  
  148.     return 0;
  149. }
  150.  
  151.  
  152. /*
  153. Output with MSVC2013 x64 on Ivy Bridge 3.4 Ghz:
  154.  
  155. (billions of calls per second)
  156. size = 1:
  157.   0.261  (Paul R)
  158.   0.249  (Paul R x64)
  159.   0.453  (stgatilov)
  160. size = 2:
  161.   0.201  (Paul R)
  162.   0.248  (Paul R x64)
  163.   0.45  (stgatilov)
  164. size = 3:
  165.   0.153  (Paul R)
  166.   0.249  (Paul R x64)
  167.   0.45  (stgatilov)
  168. size = 4:
  169.   0.132  (Paul R)
  170.   0.248  (Paul R x64)
  171.   0.45  (stgatilov)
  172. size = 5:
  173.   0.111  (Paul R)
  174.   0.248  (Paul R x64)
  175.   0.453  (stgatilov)
  176. size = 6:
  177.   0.0981  (Paul R)
  178.   0.248  (Paul R x64)
  179.   0.453  (stgatilov)
  180. size = 7:
  181.   0.0863  (Paul R)
  182.   0.248  (Paul R x64)
  183.   0.45  (stgatilov)
  184. size = 8:
  185.   0.0782  (Paul R)
  186.   0.249  (Paul R x64)
  187.   0.45  (stgatilov)
  188. size = 9:
  189.   0.0712  (Paul R)
  190.   0.191  (Paul R x64)
  191.   0.453  (stgatilov)
  192. size = 10:
  193.   0.0652  (Paul R)
  194.   0.191  (Paul R x64)
  195.   0.453  (stgatilov)
  196. size = 11:
  197.   0.0599  (Paul R)
  198.   0.191  (Paul R x64)
  199.   0.45  (stgatilov)
  200. size = 12:
  201.   0.0559  (Paul R)
  202.   0.191  (Paul R x64)
  203.   0.453  (stgatilov)
  204. size = 13:
  205.   0.0474  (Paul R)
  206.   0.19  (Paul R x64)
  207.   0.453  (stgatilov)
  208. size = 14:
  209.   0.0489  (Paul R)
  210.   0.191  (Paul R x64)
  211.   0.45  (stgatilov)
  212. size = 15:
  213.   0.0453  (Paul R)
  214.   0.191  (Paul R x64)
  215.   0.317  (stgatilov)
  216. size = 16:
  217.   0.0435  (Paul R)
  218.   0.191  (Paul R x64)
  219.   0.317  (stgatilov)
  220. size = 17:
  221.   0.0392  (Paul R)
  222.   0.121  (Paul R x64)
  223.   0.317  (stgatilov)
  224. size = 18:
  225.   0.0373  (Paul R)
  226.   0.122  (Paul R x64)
  227.   0.318  (stgatilov)
  228. size = 19:
  229.   0.0353  (Paul R)
  230.   0.121  (Paul R x64)
  231.   0.317  (stgatilov)
  232. size = 20:
  233.   0.0341  (Paul R)
  234.   0.122  (Paul R x64)
  235.   0.315  (stgatilov)
  236. size = 21:
  237.   0.0327  (Paul R)
  238.   0.121  (Paul R x64)
  239.   0.32  (stgatilov)
  240. size = 22:
  241.   0.0313  (Paul R)
  242.   0.122  (Paul R x64)
  243.   0.317  (stgatilov)
  244. size = 23:
  245.   0.0302  (Paul R)
  246.   0.121  (Paul R x64)
  247.   0.32  (stgatilov)
  248. size = 24:
  249.   0.0291  (Paul R)
  250.   0.122  (Paul R x64)
  251.   0.318  (stgatilov)
  252. size = 25:
  253.   0.028  (Paul R)
  254.   0.107  (Paul R x64)
  255.   0.317  (stgatilov)
  256. size = 26:
  257.   0.0271  (Paul R)
  258.   0.107  (Paul R x64)
  259.   0.317  (stgatilov)
  260. size = 27:
  261.   0.0262  (Paul R)
  262.   0.107  (Paul R x64)
  263.   0.318  (stgatilov)
  264. size = 28:
  265.   0.0253  (Paul R)
  266.   0.107  (Paul R x64)
  267.   0.315  (stgatilov)
  268. size = 29:
  269.   0.0246  (Paul R)
  270.   0.107  (Paul R x64)
  271.   0.235  (stgatilov)
  272. size = 30:
  273.   0.0238  (Paul R)
  274.   0.107  (Paul R x64)
  275.   0.235  (stgatilov)
  276. size = 31:
  277.   0.023  (Paul R)
  278.   0.107  (Paul R x64)
  279.   0.235  (stgatilov)
  280. size = 32:
  281.   0.0224  (Paul R)
  282.   0.107  (Paul R x64)
  283.   0.235  (stgatilov)
  284.  
  285. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement