文字列から IPv4 アドレスを取得する最速の方法
問題の元のコード:
UINT32 GetIP(const char *p) { UINT32 dwIP=0,dwIP_Part=0; while(true) { if(p[0] == 0) { dwIP = (dwIP << 8) | dwIP_Part; break; } if(p[0]=='.') { dwIP = (dwIP << 8) | dwIP_Part; dwIP_Part = 0; p++; } dwIP_Part = (dwIP_Part*10)+(p[0]-'0'); p++; } return dwIP; }
より高速なベクトル化された解決策:
x86 命令セットを利用する、問題に対するより効率的な解決策を以下に示します:
UINT32 MyGetIP(const char *str) { // Load and convert input __m128i input = _mm_lddqu_si128((const __m128i*)str); input = _mm_sub_epi8(input, _mm_set1_epi8('0')); // Generate shuffled array __m128i cmp = input; UINT32 mask = _mm_movemask_epi8(cmp); __m128i shuf = shuffleTable[mask]; __m128i arr = _mm_shuffle_epi8(input, shuf); // Calculate coefficients __m128i coeffs = _mm_set_epi8(0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1); // Multiply and accumulate __m128i prod = _mm_maddubs_epi16(coeffs, arr); prod = _mm_hadd_epi16(prod, prod); // Reorder result __m128i imm = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 4, 2, 0); prod = _mm_shuffle_epi8(prod, imm); // Extract result return _mm_extract_epi32(prod, 0); }
ShuffleTable の事前計算:
void MyInit() { int len[4]; for (len[0] = 1; len[0] <= 3; len[0]++) for (len[1] = 1; len[1] <= 3; len[1]++) for (len[2] = 1; len[2] <= 3; len[2]++) for (len[3] = 1; len[3] <= 3; len[3]++) { int slen = len[0] + len[1] + len[2] + len[3] + 4; int rem = 16 - slen; for (int rmask = 0; rmask < 1<<rem; rmask++) { int mask = 0; char shuf[16] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; int pos = 0; for (int i = 0; i < 4; i++) { for (int j = 0; j < len[i]; j++) { shuf[(3-i) * 4 + (len[i]-1-j)] = pos; pos++; } mask ^= (1<<pos); pos++; } mask ^= (rmask<<slen); _mm_store_si128(&shuffleTable[mask], _mm_loadu_si128((__m128i*)shuf)); } } }
評価:
このソリューションはベクトル化技術により大幅に高速化し、元のコードの 7.8 倍のパフォーマンスを上回ります。 3.4 GHz プロセッサの単一コアで 1 秒あたり約 3 億 3,600 万の IP アドレスを処理できます。
以上がベクトル化技術を使用して、IPv4 アドレスの文字列から整数への変換を高速化するにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。