2016-06-18 9 views
10

पर कॉल करते समय सीएलआर मेरे मुकाबले तेजी से कैसा है, जब मुझे कुछ आश्चर्यजनक (मुझे) मिला तो मैंने टाइमस्टैम्प उत्पन्न करने के विभिन्न तरीकों का परीक्षण किया।विंडोज एपीआई

विंडोज के GetSystemTimeAsFileTime पी का उपयोग कर कॉलिंग/आह्वान DateTime.UtcNow कि आंतरिक रूप से एक ही GetSystemTimeAsFileTime के लिए CLR के आवरण का उपयोग करता बुला की अपेक्षा 3 गुना के बारे में धीमी है।

यह कैसे हो सकता है?

यहाँ DateTime.UtcNow's implementation है:

public static DateTime UtcNow { 
    get { 
     long ticks = 0; 
     ticks = GetSystemTimeAsFileTime(); 
     return new DateTime(((UInt64)(ticks + FileTimeOffset)) | KindUtc); 
    } 
} 

[MethodImplAttribute(MethodImplOptions.InternalCall)] // Implemented by the CLR 
internal static extern long GetSystemTimeAsFileTime(); 

कोर CLR के wrapper for GetSystemTimeAsFileTime:

FCIMPL0(INT64, SystemNative::__GetSystemTimeAsFileTime) 
{ 
    FCALL_CONTRACT; 

    INT64 timestamp; 

    ::GetSystemTimeAsFileTime((FILETIME*)&timestamp); 

#if BIGENDIAN 
    timestamp = (INT64)(((UINT64)timestamp >> 32) | ((UINT64)timestamp << 32)); 
#endif 

    return timestamp; 
} 
FCIMPLEND; 

मेरे परीक्षण कोड BenchmarkDotNet उपयोग:

public class Program 
{ 
    static void Main() => BenchmarkRunner.Run<Program>(); 

    [Benchmark] 
    public DateTime UtcNow() => DateTime.UtcNow; 

    [Benchmark] 
    public long GetSystemTimeAsFileTime() 
    { 
     long fileTime; 
     GetSystemTimeAsFileTime(out fileTime); 
     return fileTime; 
    } 

    [DllImport("kernel32.dll")] 
    public static extern void GetSystemTimeAsFileTime(out long systemTimeAsFileTime); 
} 

और परिणाम:

    Method |  Median | StdDev | 
------------------------ |----------- |---------- | 
GetSystemTimeAsFileTime | 14.9161 ns | 1.0890 ns | 
        UtcNow | 4.9967 ns | 0.2788 ns | 
+2

CLR यह सीधे कॉल कर सकते हैं। Pinvoke marshalling परत के माध्यम से चला जाता है। –

+0

@ डेविड हेफरनन जब भी पैरामीटर को मार्शलिंग की आवश्यकता नहीं है? – i3arnon

+1

@ i3arnon: इसे साबित करने के लिए उन्हें कुछ विश्लेषण करना है। –

उत्तर

4

सीएलआर परिणाम प्राप्त करने के लिए लगभग स्थानीय (स्वचालित, ढेर) चर के लिए निश्चित रूप से एक सूचक को पास करता है। ढेर को कॉम्पैक्ट या स्थानांतरित नहीं किया जाता है, इसलिए स्मृति को पिन करने की कोई आवश्यकता नहीं है, आदि, और मूल कंपाइलर का उपयोग करते समय, ऐसी चीजें किसी भी तरह समर्थित नहीं होती हैं, इसलिए उनके लिए कोई ओवरहेड नहीं है।

सी # हालांकि, पी/आवेषण घोषणा कचरा-एकत्रित ढेर में रहने वाले एक प्रबंधित वर्ग उदाहरण के सदस्य को पास करने के साथ संगत है। पी/आवेक को उस उदाहरण को पिन करना होगा या अन्यथा ओएस फ़ंक्शन लिखने के दौरान आउटपुट बफर को ले जाने से पहले जोखिम उठाना होगा। भले ही आप ढेर पर संग्रहीत चर को पास करते हैं, फिर भी पी/आवेक को परीक्षण करना चाहिए और यह देखना चाहिए कि क्या पॉइंटर कचरे में है, जो पिनिंग कोड के चारों ओर शाखा बना सकता है, इससे पहले कि समान मामले के लिए गैर-शून्य ओवरहेड भी हो।

यह आप

[DllImport("kernel32.dll")] 
public unsafe static extern void GetSystemTimeAsFileTime(long* pSystemTimeAsFileTime); 

का उपयोग कर बेहतर परिणाम प्राप्त कर सकता है कि अब पूरी तरह से है कि सेट अपने कोड की जिम्मेदारी out पैरामीटर, पी/आह्वान नहीं रह गया है अलियासिंग और ढेर संघनन से निपटने के लिए है, कि है हटाकर संभव है सूचक ऊपर।

4

जब प्रबंधित कोड अप्रबंधित कोड का आह्वान करता है तो एक स्टैक चलना सुनिश्चित करता है कि कॉलिंग कोड में UnmanagedCode अनुमति है जो ऐसा करने में सक्षम है।

उस स्टैक पैदल रन-टाइम पर किया जाता है और इसमें प्रदर्शन में पर्याप्त लागत होती है।

यह (वहाँ अभी भी एक JIT संकलन समय से एक है) रन-टाइम चेक निकालने के लिए SuppressUnmanagedCodeSecurity attribute का उपयोग करके संभव है:

:

[SuppressUnmanagedCodeSecurity] 
[DllImport("kernel32.dll")] 
public static extern void GetSystemTimeAsFileTime(out long systemTimeAsFileTime); 

यह CLR के दिशा में आधे रास्ते के बारे में मेरे कार्यान्वयन लाता है

    Method | Median | StdDev | 
------------------------ |---------- |---------- | 
GetSystemTimeAsFileTime | 9.0569 ns | 0.7950 ns | 
        UtcNow | 5.0191 ns | 0.2682 ns | 

ध्यान रखें कि ऐसा करना बेहद जोखिम भरा सुरक्षा-वार हो सकता है।

इसके अलावा unsafe बेन वोइट के रूप में उपयोग करते हुए सुझाव दिया है कि यह आधे रास्ते फिर से लाता है:

    Method | Median | StdDev | 
------------------------ |---------- |---------- | 
GetSystemTimeAsFileTime | 6.9114 ns | 0.5432 ns | 
        UtcNow | 5.0226 ns | 0.0906 ns | 
संबंधित मुद्दे