दिलचस्प पोस्ट
त्रुटि: कार्य निष्पादन के लिए विफल ': ProjectName: mergeDebugResources' > क्रंचिंग की कुछ फ़ाइल * विफल रही, लॉग देखें एंड्रॉइड एप्लीकेशन में "बंडल" क्या है जब मैं javax.tools.javaCompiler का उपयोग करता हूँ, तब वर्गपथ को कैसे सेट किया जाए? अजगर subprocess.check_output की पहली तर्क और शेल = सत्य को समझना बनाम क्लिक विधियों पर jquery Dict.clear () के बीच का अंतर और {} पायथन में निर्दिष्ट करना PHP के DOM और SimpleXML एक्सटेंशन के बीच अंतर क्या है? स्कला बनाम पायथन के लिए स्पार्क प्रदर्शन Php स्क्रिप्ट के दोहरे उद्धरण गूंज UIImage iPhone पर फाइल नाम के साथ छवि को सहेज रहा है एक एमकॉलॉजीन में एक बिंदु का पता लगाया IOS7 (CGPathContainsPoint) के साथ तोड़ दिया कैसे VBA के साथ निर्दिष्ट सेल स्थिति पर एक चित्र Excel में डालें सेलेनियम वेबड्राइवर के साथ छिपे हुए तत्वों से पाठ कैसे पढ़ा जाए? जांचें कि क्या गैट में पुल की ज़रूरत है जावास्क्रिप्ट: जावास्क्रिप्ट या सर्वलेट का उपयोग करके बाइट सरणी से छवि कैसे प्रदर्शित करें?

स्ट्रिंग से आईपीवी 4 पता पाने का सबसे तेज़ तरीका

मेरे पास निम्न कोड है जो inet_addr से लगभग 7 गुना तेज है I मैं सोच रहा था कि क्या इसे बेहतर बनाने के लिए एक बेहतर तरीका है या यदि एक तेज वैकल्पिक मौजूद है

इस कोड के लिए आवश्यक है कि एक वैध नल समाप्त आईपीवी 4 पते को कोई सफेद स्थान के साथ नहीं दिया गया है, जो मेरे मामले में हमेशा होता है, इसलिए मैंने उस स्थिति के लिए अनुकूलित किया। आम तौर पर आपको अधिक त्रुटि की जांच होनी चाहिए, लेकिन यदि निम्नलिखित को तेज़ी से या तेजी से वैकल्पिक बनाने का एक तरीका है तो मैं इसकी सराहना करता हूं।

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; } 

वेब के समाधान से एकत्रित समाधान "स्ट्रिंग से आईपीवी 4 पता पाने का सबसे तेज़ तरीका"

चूंकि हम आईपी एड्रेस पार्सिंग के थ्रूपुट को अधिकतम करने के बारे में बात कर रहे हैं, इसलिए मैं एक वैक्टरयुक्त समाधान का उपयोग करने का सुझाव देता हूं।

यहां x 86- विशिष्ट तेज समाधान है (SSE4.1 की आवश्यकता है, या कम से कम SSSE3 को गरीबों के लिए):

 __m128i shuffleTable[65536]; //can be reduced 256x times, see @IwillnotexistIdonotexist UINT32 MyGetIP(const char *str) { __m128i input = _mm_lddqu_si128((const __m128i*)str); //"192.167.1.3" 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 __m128i cmp = input; //...X...XXXX... (signs) UINT32 mask = _mm_movemask_epi8(cmp); //6792 - magic index __m128i shuf = shuffleTable[mask]; //10 -1 -1 -1 8 -1 -1 -1 6 5 4 -1 2 1 0 -1 __m128i arr = _mm_shuffle_epi8(input, shuf); //3 0 0 0 | 1 0 0 0 | 7 6 1 0 | 2 9 1 0 __m128i coeffs = _mm_set_epi8(0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1); __m128i prod = _mm_maddubs_epi16(coeffs, arr); //3 0 | 1 0 | 67 100 | 92 100 prod = _mm_hadd_epi16(prod, prod); //3 | 1 | 167 | 192 | ? | ? | ? | ? __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); //3 1 167 192 0 0 0 0 0 0 0 0 0 0 0 0 return _mm_extract_epi32(prod, 0); // return (UINT32(_mm_extract_epi16(prod, 1)) << 16) + UINT32(_mm_extract_epi16(prod, 0)); //no SSE 4.1 } 

और यहां shuffleTable लिए आवश्यक सटीक shuffleTable :

 void MyInit() { memset(shuffleTable, -1, sizeof(shuffleTable)); 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 rmask = (1<<rem)-1; //note: only maximal rmask is possible if strings are zero-padded 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)); } } } 

परीक्षण के साथ पूर्ण कोड यहां उपलब्ध है । आइवी ब्रिज प्रोसेसर पर यह प्रिंट करता है:

 C0A70103 Time = 0.406 (1556701184) Time = 3.133 (1556701184) 

इसका मतलब है कि ओपी द्वारा कोड की तुलना में थ्रूपूट के संदर्भ में सुझाए गए समाधान 7.8 गुना तेज है। यह 336 लाख पतों प्रति सेकंड (3.4 गीगा की एकल कोर) की प्रक्रिया करता है।

अब मैं यह समझाने की कोशिश करता हूँ कि यह कैसे काम करता है। ध्यान दें कि लिस्टिंग के प्रत्येक पंक्ति पर आप मूल्य की सामग्री को केवल गणना कर सकते हैं सभी सरणियों को छूटे-एंडियन ऑर्डर में मुद्रित किया जाता है (हालांकि इन्टरिनिक्स बड़े-एंडियन का इस्तेमाल करते हैं)

सबसे पहले, हम 16 बाइट्स को lddqu निर्देश द्वारा अनजान पता से lddqu करते हैं। ध्यान दें कि 64-बिट मोड मेमोरी में 16-बाइट विखंडन द्वारा आवंटित किया जाता है, इसलिए यह स्वचालित रूप से अच्छी तरह से काम करता है। 32-बिट पर यह सैद्धांतिक रूप से सीमा तक पहुंच के बाहर के मुद्दों का कारण हो सकता है। हालांकि मुझे विश्वास नहीं है कि यह वास्तव में कर सकता है। बाद के कोड बाद के अंत बाइट्स में मूल्यों की परवाह किए बिना ठीक से काम करेगा। वैसे भी, आप बेहतर यह सुनिश्चित करना चाहते हैं कि प्रत्येक आईपी पते के भंडारण के कम से कम 16 बाइट्स हों।

फिर हम सभी वर्णों से '0' घटा देते हैं। उसके बाद '।' -2 में बदल जाता है, और शून्य -48 में बदल जाता है, सभी अंक गैर-नकारात्मक होते हैं अब हम _mm_movemask_epi8 साथ सभी बाइट्स के संकेतों का _mm_movemask_epi8

इस मुखौटा के मूल्य के आधार पर, हम लुकअप तालिका shuffleTable से एक shuffleTable 16-बाइट फेरबदल मास्क shuffleTable । टेबल काफी बड़ी है: 1 एमबी कुल। और यह प्रीकंपूप्ट के लिए कुछ समय लगता है। हालांकि, यह CPU कैश में अनमोल स्पेस नहीं लेता है, क्योंकि इस तालिका के केवल 81 तत्व वास्तव में उपयोग किए जाते हैं। इसका कारण यह है कि आईपी पते के प्रत्येक भाग में एक, दो, तीन अंक लंबा => इसलिए कुल में 81 प्रकार हैं। ध्यान दें कि स्ट्रिंग के अंत के बाद यादृच्छिक कचरा बाइट सिद्धांत रूप में लुकअप तालिका में स्मृति पदचिह्न बढ़ा सकते हैं।

संपादित करें : आप @IwillnotexistIdonotexist द्वारा संशोधित संस्करण को टिप्पणियों में पा सकते हैं, जो केवल 4 केबी आकार के लुकअप तालिका का उपयोग करता है (हालांकि यह थोड़ा धीमा है)।

सरल _mm_shuffle_epi8 आंतरिक हमें हमारे फेरबदल मुखौटा के साथ बाइट पुन: क्रमबद्ध करने की अनुमति देता है। नतीजतन, एक्सएमएम रजिस्टर में चार 4-बाइट ब्लॉकों होते हैं, प्रत्येक ब्लॉक में छोटी-एंडियन ऑर्डर में अंक होते हैं। हम प्रत्येक ब्लॉक को 16-बिट संख्या में _mm_maddubs_epi16 द्वारा _mm_maddubs_epi16 उसके बाद _mm_hadd_epi16 । फिर हम रजिस्टर के बाइट्स को पुन: क्रमित करते हैं, ताकि पूरे आईपी पते में कम 4 बाइट्स रह जाए।

अंत में, हम एक्सएमएम रजिस्टर से कम 4 बाइट्स को जीपी रजिस्टर से निकालें यह SSE4.1 आंतरिक ( _mm_extract_epi32 ) के साथ किया जाता है यदि आपके पास यह नहीं है, तो इसे दूसरी लाइन के साथ _mm_extract_epi16 का उपयोग करके _mm_extract_epi16 , लेकिन यह थोड़ी धीमी गति से चला जाएगा।

अंत में, यहां जनरेटेड असेंबली (एमएसवीसी2013) है, ताकि आप जांच सकें कि आपका कंपाइलर कुछ भी संदिग्ध उत्पन्न नहीं करता है:

 lddqu xmm1, XMMWORD PTR [rcx] psubb xmm1, xmm6 pmovmskb ecx, xmm1 mov ecx, ecx //useless, see @PeterCordes and @IwillnotexistIdonotexist add rcx, rcx //can be removed, see @EvgenyKluev pshufb xmm1, XMMWORD PTR [r13+rcx*8] movdqa xmm0, xmm8 pmaddubsw xmm0, xmm1 phaddw xmm0, xmm0 pshufb xmm0, xmm7 pextrd eax, xmm0, 0 

पीएस यदि आप अभी भी इसे पढ़ रहे हैं, तो टिप्पणियां देखें)

विकल्पों के लिए: यह आपके जैसा है, लेकिन कुछ त्रुटि जांच के साथ:

 #include <iostream> #include <string> #include <cstdint> uint32_t getip(const std::string &sip) { uint32_t r=0, b, p=0, c=0; const char *s; s = sip.c_str(); while (*s) { r<<=8; b=0; while (*s&&((*s==' ')||(*s=='\t'))) s++; while (*s) { if ((*s==' ')||(*s=='\t')) { while (*s&&((*s==' ')||(*s=='\t'))) s++; if (*s!='.') break; } if (*s=='.') { p++; s++; break; } if ((*s>='0')&&(*s<='9')) { b*=10; b+=(*s-'0'); s++; } } if ((b>255)||(*s=='.')) return 0; r+=b; c++; } return ((c==4)&&(p==3))?r:0; } void testip(const std::string &sip) { uint32_t nIP=0; nIP = getip(sip); std::cout << "\nsIP = " << sip << " --> " << std::hex << nIP << "\n"; } int main() { testip("192.167.1.3"); testip("292.167.1.3"); testip("192.267.1.3"); testip("192.167.1000.3"); testip("192.167.1.300"); testip("192.167.1."); testip("192.167.1"); testip("192.167..1"); testip("192.167.1.3."); testip("192.1 67.1.3."); testip("192 . 167 . 1 . 3"); testip(" 192 . 167 . 1 . 3 "); return 0; }