2014-10-04 7 views
9

मैं अपने कुछ पुराने (और विशेष रूप से Win32 उन्मुख) सामानों को देख रहा हूं और इसे अधिक आधुनिक/पोर्टेबल बनाने के बारे में सोच रहा हूं - यानी सी ++ 11 में कुछ व्यापक रूप से पुन: प्रयोज्य भागों को पुन: कार्यान्वित करना। इन भागों में से एक utf8 और utf16 के बीच कनवर्ट है। Win32 एपीआई में मैं MultiByteToWideChar/WideCharToMultiByte का उपयोग कर रहा हूं, उस सामग्री को सी ++ 11 में नमूना कोड का उपयोग करके पोर्ट को बंद करने का प्रयास कर रहा हूं: https://stackoverflow.com/a/14809553। वहाँ कुछ कोड के साथ गलत है - परिणामutf8 <-> utf16: codecvt खराब प्रदर्शन

रिलीज निर्माण (, MSVS 2013 तक संकलित कोर i7 3610QM पर चलने)

stdlib     = 1587.2 ms 
Win32     = 127.2 ms 

डीबग निर्माण

stdlib     = 5733.8 ms 
Win32     = 127.2 ms 

सवाल है ? अगर सब कुछ ठीक लगता है - क्या इस तरह के प्रदर्शन अंतर के लिए कुछ अच्छा कारण है?

टेस्ट कोड के नीचे है:

#include <iostream> 
#include <fstream> 
#include <string> 
#include <iterator> 
#include <clocale> 
#include <codecvt> 

#define XU_BEGIN_TIMER(NAME)      \ 
    {           \ 
     LARGE_INTEGER __freq;     \ 
     LARGE_INTEGER __t0;     \ 
     LARGE_INTEGER __t1;     \ 
     double   __tms;     \ 
     const char*  __tname = NAME;   \ 
     char   __tbuf[0xff];   \ 
               \ 
     QueryPerformanceFrequency(&__freq);  \ 
     QueryPerformanceCounter(&__t0);   

#define XU_END_TIMER()        \ 
     QueryPerformanceCounter(&__t1);   \ 
     __tms = (__t1.QuadPart - __t0.QuadPart) * 1000.0/__freq.QuadPart; \ 
     sprintf_s(__tbuf, sizeof(__tbuf), " %-24s = %6.1f ms\n", __tname, __tms); \ 
     OutputDebugStringA(__tbuf);    \ 
     printf(__tbuf);       \ 
    } 

std::string read_utf8() { 
    std::ifstream infile("C:/temp/UTF-8-demo.txt"); 
    std::string fileData((std::istreambuf_iterator<char>(infile)), 
         std::istreambuf_iterator<char>()); 
    infile.close(); 

    return fileData; 
} 

void testMethod() { 
    std::setlocale(LC_ALL, "en_US.UTF-8"); 
    std::string source = read_utf8(); 
    { 
     std::string utf8; 

     XU_BEGIN_TIMER("stdlib") { 
      for(int i = 0; i < 1000; i++) { 
       std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert2utf16; 
       std::u16string utf16 = convert2utf16.from_bytes(source); 

       std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert2utf8; 
       utf8 = convert2utf8.to_bytes(utf16); 
      } 
     } XU_END_TIMER(); 

     FILE* output = fopen("c:\\temp\\utf8-std.dat", "wb"); 
     fwrite(utf8.c_str(), 1, utf8.length(), output); 
     fclose(output); 
    } 

    char* utf8 = NULL; 
    int cchA = 0; 

    { 
     XU_BEGIN_TIMER("Win32") { 
      for(int i = 0; i < 1000; i++) { 
       WCHAR* utf16 = new WCHAR[source.length() + 1]; 
       int cchW; 
       utf8 = new char[source.length() + 1]; 

       cchW = MultiByteToWideChar(
        CP_UTF8, 0, source.c_str(), source.length(), 
        utf16, source.length() + 1); 

       cchA = WideCharToMultiByte(
        CP_UTF8, 0, utf16, cchW, 
        utf8, source.length() + 1, NULL, false); 

       delete[] utf16; 
       if(i != 999) 
        delete[] utf8; 
      } 
     } XU_END_TIMER(); 

     FILE* output = fopen("c:\\temp\\utf8-win.dat", "wb"); 
     fwrite(utf8, 1, cchA, output); 
     fclose(output); 

     delete[] utf8; 
    } 
} 
+0

आपका Win32 कोड बफर को सही ढंग से आवंटित नहीं कर रहा है। यूटीएफ -8 और यूटीएफ -16 में उनके डेटा की लंबाई के बीच 1-से-1 संबंध नहीं है। आपको आवश्यक बफर आकार की गणना करने के लिए एक बार 'मल्टीबाइट टॉइडहायर'/'वाइडछारटो मल्टीबीटाइट' कॉल करना चाहिए, फिर बफर आवंटित करना चाहिए, फिर वास्तविक रूपांतरण करने के लिए फिर से कॉल करें। तो यह थोड़ा सा समय को प्रभावित करता है। –

+6

Win32 चूंकि विस्टा एसएसई को आंतरिक प्रभाव से आंतरिक रूप से उपयोग करता है, कुछ बहुत कम यूटीएफ ट्रांसकोडर्स करते हैं। इसे हरा करना मुश्किल होगा। –

+0

@ रेमी लेबेउ: हाँ, अगर मैं अतिरिक्त आवंटित नहीं करना चाहता (वास्तव में अस्थायी मेमोरी) मुझे मल्टीबाइट टॉवाइडर/वाइडरहर्टोमोल्टीबीट को एक और बार कॉल करने की आवश्यकता है - यह 127 * 2 = 250ms के आसपास कुछ के लिए win32 उपयोगकेस लाएगा। यह अभी भी stdlib से 6.5 गुना तेज है। –

उत्तर

4

Win32 के UTF8 विस्टा के बाद से ट्रांसकोड महान प्रभाव के लिए आंतरिक रूप से SSE का उपयोग करता है, कुछ बहुत कुछ अन्य UTF transcoders है। मुझे संदेह है कि यहां तक ​​कि सबसे ज्यादा अनुकूलित पोर्टेबल कोड के साथ हरा देना असंभव होगा।

हालांकि, यह संख्या codecvt के लिए दी गई है, यदि यह 10x समय ले रहा है, तो यह असाधारण रूप से धीमा है, और एक निष्पक्ष कार्यान्वयन का सुझाव देता है। अपने स्वयं के यूटीएफ -8 डीकोडर लिखते समय, मैं Win32 के perx 2-3x के भीतर पहुंचने में सक्षम था। यहां सुधार के लिए बहुत सी जगह है, लेकिन इसे प्राप्त करने के लिए आपको कोडेकवेट को लागू करने की आवश्यकता होगी।

+3

_Win32 का यूटीएफ 8 ट्रांसकोड क्योंकि विस्टा एसएसई को आंतरिक प्रभाव से आंतरिक प्रभाव में उपयोग करता है ..._ - क्या आपके पास कोई संदर्भ है? – polyvertex

7

अपने स्वयं के परीक्षण में, मैंने पाया कि wstring_convert के लिए कन्स्ट्रक्टर कॉल कम से कम विंडोज पर है। जैसा कि अन्य उत्तरों सुझाव देते हैं, आप शायद मूल विंडोज कार्यान्वयन को हरा करने के लिए संघर्ष करेंगे, लेकिन लूप के बाहर कनवर्टर बनाने के लिए अपने कोड को संशोधित करने का प्रयास करें। मुझे आशा है कि आप विशेष रूप से डीबग बिल्ड में 5x और 20x के बीच सुधार देखेंगे।

+1

यह वास्तव में जिस समस्या का सामना कर रहा था, वह साबित हुआ। कन्स्ट्रक्टर स्थिर बना दिया: उछाल! –

+0

अब सवाल यह है - क्या आप उस स्थिर वस्तु को कई धागे से सुरक्षित रूप से उपयोग कर सकते हैं? ;) –

संबंधित मुद्दे