stgatilov

Vectorized unsafe IP address parsing

Jul 28th, 2015
543
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <stdio.h>
  2. #include <time.h>
  3. #include <vector>
  4. #include <string>
  5. #include <algorithm>
  6. #include <smmintrin.h>
  7.  
  8. typedef unsigned int UINT32;
  9.  
  10. UINT32 GetIP(const char *p)
  11. {
  12.     UINT32 dwIP=0,dwIP_Part=0;
  13.     while(true)
  14.     {
  15.         if(p[0] == 0)
  16.         {
  17.             dwIP = (dwIP << 8) | dwIP_Part;
  18.             break;
  19.         }
  20.         if(p[0]=='.')
  21.         {      
  22.             dwIP = (dwIP << 8) | dwIP_Part;                    
  23.             dwIP_Part = 0;
  24.            p++;
  25.         }
  26.         dwIP_Part = (dwIP_Part*10)+(p[0]-'0');
  27.         p++;
  28.     }
  29.     return dwIP;
  30. }
  31.  
  32. __m128i shuffleTable[65536];    //perhaps can be reduced 32x times, see @IwillnotexistIdonotexist
  33. void MyInit() {
  34.     memset(shuffleTable, -1, sizeof(shuffleTable));
  35.     int len[4];
  36.     for (len[0] = 1; len[0] <= 3; len[0]++)
  37.         for (len[1] = 1; len[1] <= 3; len[1]++)
  38.             for (len[2] = 1; len[2] <= 3; len[2]++)
  39.                 for (len[3] = 1; len[3] <= 3; len[3]++) {
  40.                     int slen = len[0] + len[1] + len[2] + len[3] + 4;
  41.                     int rem = 16 - slen;
  42.                     for (int rmask = 0; rmask < 1<<rem; rmask++) {
  43. //                    { int rmask = (1<<rem)-1;    //note: only maximal rmask is possible if strings are zero-padded
  44.                         int mask = 0;
  45.                         char shuf[16] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
  46.                         int pos = 0;
  47.                         for (int i = 0; i < 4; i++) {
  48.                             for (int j = 0; j < len[i]; j++) {
  49.                                 shuf[(3-i) * 4 + (len[i]-1-j)] = pos;
  50.                                 pos++;
  51.                             }
  52.                             mask ^= (1<<pos);
  53.                             pos++;
  54.                         }
  55.                         mask ^= (rmask<<slen);
  56.                         _mm_store_si128(&shuffleTable[mask], _mm_loadu_si128((__m128i*)shuf));
  57.                     }
  58.                 }
  59. }
  60. UINT32 MyGetIP(const char *str) {
  61.     __m128i input = _mm_lddqu_si128((const __m128i*)str);   //"192.167.1.3"
  62. //  for (int i = 0; i < 16; i++) printf("%c ", input.m128i_u8[i]); printf("\n");
  63.     input = _mm_sub_epi8(input, _mm_set1_epi8('0'));        //1 9 2 254 1 6 7 254 1 254 3 208 245 0 8 40
  64. //  for (int i = 0; i < 16; i++) printf("%d ", int(input.m128i_u8[i])); printf("\n");
  65.     __m128i cmp = input;                                    //...X...X.X.XX...  (signs)
  66. //  for (int i = 0; i < 16; i++) printf("%c", cmp.m128i_i8[i] < 0 ? 'X' : '.'); printf("\n");
  67.     UINT32 mask = _mm_movemask_epi8(cmp);                   //6792 - magic index
  68. //  printf("%d\n", mask);
  69.     __m128i shuf = shuffleTable[mask];                      //10 -1 -1 -1 8 -1 -1 -1 6 5 4 -1 2 1 0 -1
  70. //  for (int i = 0; i < 16; i++) printf("%d ", int(shuf.m128i_i8[i])); printf("\n");
  71.     __m128i arr = _mm_shuffle_epi8(input, shuf);            //3 0 0 0 | 1 0 0 0 | 7 6 1 0 | 2 9 1 0
  72. //  for (int i = 0; i < 16; i++) printf("%d ", int(arr.m128i_u8[i])); printf("\n");
  73.     __m128i coeffs = _mm_set_epi8(0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1);
  74.     __m128i prod = _mm_maddubs_epi16(coeffs, arr);          //3 0 | 1 0 | 67 100 | 92 100
  75. //  for (int i = 0; i < 8; i++) printf("%d ", int(prod.m128i_u16[i])); printf("\n");
  76.     prod = _mm_hadd_epi16(prod, prod);                      //3 | 1 | 167 | 192 | ? | ? | ? | ?
  77. //  for (int i = 0; i < 4; i++) printf("%d ", int(prod.m128i_u16[i])); printf("\n");
  78.     __m128i imm = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 4, 2, 0);
  79.     prod = _mm_shuffle_epi8(prod, imm);                     //3 1 167 192 0 0 0 0 0 0 0 0 0 0 0 0
  80. //  for (int i = 0; i < 4; i++) printf("%d ", int(prod.m128i_u8[i])); printf("\n");
  81.     return _mm_extract_epi32(prod, 0);
  82. //  return (UINT32(_mm_extract_epi16(prod, 1)) << 16) + UINT32(_mm_extract_epi16(prod, 0)); //no SSE 4.1
  83. }
  84.  
  85. static const int CNT = 16<<10;
  86.  
  87. int main() {
  88.   MyInit();
  89.   printf("%08X\n", MyGetIP("192.167.1.3"));
  90. //  return 0;
  91.  
  92.   std::vector<std::string> samples;
  93.   for (int i = 0; i < CNT; i++) {
  94.     std::string str;
  95.     for (int j = 0; j < 4; j++) {
  96.       if (j) str += '.';
  97.       int x = rand() % 256;
  98.       char qq[16];
  99.       sprintf(qq, "%d", x);
  100.       str += qq;
  101.     }
  102.     samples.push_back(str);
  103.  
  104. //    printf("%s\n", samples[i].c_str());
  105.     auto a = GetIP(samples.back().c_str());
  106.     auto b = MyGetIP(samples.back().c_str());
  107.     if (a != b)
  108.       printf("%s: %08X vs %08X\n", samples[i].c_str(), a, b);
  109.        
  110.   }
  111.  
  112.  
  113. {
  114.   int start = clock();
  115.   int sum = 0;
  116.   for (int i = 0; i < 1<<27; i++) {
  117.       const char *input = samples[i & (CNT-1)].c_str();
  118.       sum += MyGetIP(input);
  119.   }
  120.   int elapsed = clock() - start;
  121.   printf("Time = %0.3lf   (%d)\n", double(elapsed) / CLOCKS_PER_SEC, sum);
  122. }
  123. {
  124.   int start = clock();
  125.   int sum = 0;
  126.   for (int i = 0; i < 1<<27; i++) {
  127.       const char *input = samples[i & (CNT-1)].c_str();
  128.       sum += GetIP(input);
  129.   }
  130.   int elapsed = clock() - start;
  131.   printf("Time = %0.3lf   (%d)\n", double(elapsed) / CLOCKS_PER_SEC, sum);
  132. }
  133.  
  134.   return 0;
  135. }
RAW Paste Data