2010-12-31 15 views
8

में मिलीसेकंड सटीकता और रिज़ॉल्यूशन वाले टाइमस्टैम्प के साथ लॉग इन करें मुझे पता है कि समय सटीकता के लिए, टाइम गेटटाइम, टाइमबजिन पाइरियोड, क्वेरीरीफॉर्मेंस काउंटर इत्यादि बहुत अच्छे हैं, दोनों अच्छे रिज़ॉल्यूशन & सटीकता दोनों प्रदान करते हैं, लेकिन केवल समय-आधारित- घड़ी, घड़ी के समय के लिए कोई सीधा लिंक के साथ।विंडोज सी ++

हालांकि, मैं इस तरह की घटनाओं को समय नहीं लेना चाहता हूं। मैं एक सटीक टाइमस्टैम्प (स्थानीय समय) का उत्पादन करने में सक्षम होना चाहता हूं ताकि मैं इसे प्रत्येक फ़ाइल के लिए लॉग फ़ाइल में प्रदर्शित कर सकूं, उदाहरण के लिए 31-12-2010 12: 38: 35.345। (मुझे मिलीसेकंड सटीकता की आवश्यकता है)

मानक विंडोज टाइम फ़ंक्शंस, जैसे GetLocalTime, जबकि वे मिलीसेकंड मान देते हैं, ओएस चलने के आधार पर मिलीसेकंद रिज़ॉल्यूशन नहीं है। मैं एक्सपी का उपयोग कर रहा हूं, इसलिए मैं 15 एमएमएस रिज़ॉल्यूशन से ज्यादा बेहतर उम्मीद नहीं कर सकता।

आवश्यक आउटपुट प्राप्त करने के लिए एक बड़े ओवरहेड के बिना, मुझे दोनों दुनिया के सर्वश्रेष्ठ प्राप्त करने का एक तरीका है। अत्यधिक बड़े तरीकों/गणना का मतलब यह होगा कि लॉगर अपने ऑपरेशन के दौरान बहुत अधिक समय खाना शुरू कर देगा।

ऐसा करने का सबसे अच्छा/सरल तरीका क्या होगा?

उत्तर

5

सबसे पहले, कुछ कार्यों होने के लिए:

// ========================================================================== 
#define NOMINMAX 
#define _AFXDLL 
#include "afxwin.h"    // TRACE 
#include "windows.h"    // ULARGE_INTEGER 
#include "mmSystem.h"    // timeGetTime 
#pragma comment(lib, "Winmm.lib") // timeGetTime 

// ========================================================================== 
// convert FILETIME to ULONGLONG 
// (casting won't work on 64-bit platforms, due to alignment of FILETIME members) 
inline void ToULL(const FILETIME& ft, ULONGLONG& uft) 
{ 
    ULARGE_INTEGER uli; 
    uli.LowPart = ft.dwLowDateTime ; 
    uli.HighPart= ft.dwHighDateTime; 
    uft= uli.QuadPart; 
} 

// -------------------------------------------------------------------------- 
// convert ULONGLONG to FILETIME 
// (casting won't work on 64-bit platforms, due to alignment of FILETIME members) 
inline void ToFILETIME(const ULONGLONG& uft, FILETIME& ft) 
{ 
    ULARGE_INTEGER uli; 
    uli.QuadPart= uft; 
    ft.dwLowDateTime = uli.LowPart ; 
    ft.dwHighDateTime= uli.HighPart; 
} 

// -------------------------------------------------------------------------- 
// ULONGLONG version for GetSystemTimeAsFileTime 
inline void GetSystemTimeAsULL(ULONGLONG& uft) 
{ 
    FILETIME ft; 
    ::GetSystemTimeAsFileTime(&ft); 
    ToULL(ft, uft); 
} 

// -------------------------------------------------------------------------- 
// convert ULONGLONG to time-components 
bool ULLToSystemTime(const ULONGLONG nTime  , // [i] 
        WORD&   nYear  , // [o] 1601 - 30827 
        WORD&   nMonth  , // [o] 1 - 12 
        WORD&   nDay   , // [o] 1 - 31 
        WORD&   nHour  , // [o] 0 - 23 
        WORD&   nMinute  , // [o] 0 - 59 
        WORD&   nSecond  , // [o] 0 - 59 
        WORD&   nMilliseconds) // [o] 0 - 999 
{ 
    SYSTEMTIME sysTime; 
    FILETIME ft  ; 
    ToFILETIME(nTime, ft); 

    // the wDayOfWeek member of the SYSTEMTIME structure is ignored 
    if (0 == ::FileTimeToSystemTime(&ft, &sysTime)) 
     return false; 

    nYear  = sysTime.wYear  ; 
    nMonth  = sysTime.wMonth  ; 
    nDay   = sysTime.wDay   ; 
    nHour  = sysTime.wHour  ; 
    nMinute  = sysTime.wMinute  ; 
    nSecond  = sysTime.wSecond  ; 
    nMilliseconds= sysTime.wMilliseconds; 
    return true; 
} 

// -------------------------------------------------------------------------- 
void TraceTime(const ULONGLONG nTime) // [i] 
{ 
    WORD nYear,nMonth,nDay,nHour,nMinute,nSecond,nMilliseconds; 
    ULLToSystemTime(nTime, nYear,nMonth,nDay,nHour,nMinute,nSecond,nMilliseconds); 
    TRACE("Time: %02u-%02u-%04u %02u:%02u:%02u.%03u\n", nDay,nMonth,nYear,nHour,nMinute,nSecond,nMilliseconds); 
} 

अब, कैसे उपयोग करने के लिए:

ULONGLONG u0,u1; 
::GetSystemTimeAsULL(u0); 

// wait for tick (each 14.4mS) 
do 
{ 
    ::GetSystemTimeAsULL(u1); 
} 
while (u0==u1); 

DWORD d1= ::timeGetTime(); 

// d1 and u1 are now synchronized 

// ... do some work 

// get current time: 
ULONGLONG u2= u1+(::timeGetTime() - d1)*10000; // mSec --> HectoNanoSec 

TraceTime(u2); 

नोट आप resync चाहिए कि सटीकता बनाए रखने के लिए 2-3 मिनट में डी 1 और यू 1 बार। वास्तव में, आप इष्टतम resync अंतराल खोजने के लिए घड़ियों के बीच बहाव को माप सकते हैं।

+0

64-बिट कास्टिंग के बारे में बिंदु दिलचस्प है क्योंकि मुझे उस पर जानकारी नहीं थी। मेरा वर्तमान समाधान 32-बिट लॉक है जैसा कि मैं उपयोग कर रहा हूं (__int64 *) और ft – Dave

+0

जबकि यह वही नहीं है जो मैंने समाप्त किया है, यह निश्चित रूप से मेरे द्वारा उपयोग किए गए तर्क के निकटतम है (हालांकि 32- बिट लॉक संस्करण)। हालांकि यह जवाब शायद बेहतर है! – Dave

5

आप GetSystemAsFileTime को आजमा सकते हैं जो 100-नैनोसेकंड की इकाइयों में समय व्यक्त करता है। यह निर्धारित करने के लिए कि आप किस वास्तविक रिज़ॉल्यूशन के साथ इसे पॉप्युलेट करते हैं, आप विंडोज़ पर हैं।

वैकल्पिक विधि केवल स्थानीय समय से पूछताछ करने के लिए है और QueryPerformanceCounter का उपयोग एप्लिकेशन स्टार्टअप पर ऑफ़सेट समय-समय पर लॉक करने के लिए करें और बाद में काउंटर रीडिंग पर लागू करें।

+0

हालांकि, मेरी कठिनाई समय के समय से मिलीसेकंद मूल्य से निपटने में है, और GetLocalTime की SYSTEMTIME संरचना। मैं स्टार्टअप पर दोनों प्राप्त कर सकता हूं, लॉग टाइम पर समय गेटटाइम में एक अंतर को कैल्यूलेट कर सकता हूं, लेकिन स्वच्छ और तेज़ प्रक्रिया में GetLocalTime संरचना में उस ऑफ़सेट को कैसे लागू किया जाए, मुझे दूर कर रहा है। QueryPerformanceCounter का उपयोग करने के लिए इसे विस्तारित करने के लिए मिश्रण में एक और चर (QueryPerformanceFrequency) जोड़ता है, जिससे इसे और भी धीमा कर दिया जाता है। मुझे एक 'त्वरित' एल्गोरिदम चाहिए, ऐसा कोई नहीं जो एक सिस्टम को हॉग करेगा। – Dave

+0

@ गीगाहर्ट्ज प्रोसेसर पर मूल गणित प्रदर्शन के बारे में चिंताजनक कुछ मूर्खतापूर्ण है जब आप डिस्क पर आउटपुट कर रहे हैं जो कई कारक धीमे हैं। –

+0

आउटपुट मुख्य रूप से स्क्रीन पर है। फ़ाइल वैकल्पिक होगा, डेटाबेस आउटपुट के रूप में। प्रति सेकंड कई प्रविष्टियां भी होंगी, इसलिए मिलीसेकंड सटीकता की आवश्यकता है, इसलिए इस उदाहरण में एक अनुकूलित विधि होने की आवश्यकता है। हमारे पास gigahertz कंप्यूटर हो सकते हैं, लेकिन एक लॉगिंग सिस्टम यह सब नहीं मिलता है। मेरे पास बहुत अधिक संसाधन हैं जो अधिक संसाधनों को लेते हैं जिन्हें अक्षम अक्षम लॉगर द्वारा धीमा नहीं किया जा सकता है। – Dave

0

मैंने एक बार इसके लिए कोड लिखा था, लेकिन अंत में इसे छोड़ दिया और ओएस समय संकल्प के साथ शांति बना दी। 50 गुना के लिए एक तंग लूप में GetLocalTime और QueryPerformanceCounter दोनों कोड को कोड कहा जाता है। जब मुझे पता चलता है कि GetLocalTime के परिणाम को एक रिज़ॉल्यूशन टिक द्वारा बदला गया था, तो मुझे लगता है कि संबंधित क्वेरी से परिणामप्रष्टीकरण काउंटर उस टिक की शुरुआत के लिए काफी करीब है। इस तरह से मुझे एक सटीक समय ऑफसेट मिलता है। उस बिंदु से आगे मैं QueryPerformanceCounter को कॉल करता हूं और मुझे एक सटीक स्थानीय समय प्राप्त करने के लिए समय ऑफसेट के साथ गणित करता हूं।

अंत में मैंने तर्क दिया कि यह सब इतना परेशानी नहीं है, और मुझे वास्तव में सभी सटीकता की आवश्यकता नहीं है।

0

स्टार्टअप पर सिस्टम समय और queryperfcounter प्राप्त करने के लिए मैं क्या करूँगा। आप जानते हैं कि एक उचित सटीक प्रारंभिक बिंदु है।

फिर अपने लॉग सिस्टम में QueryPerformanceCounter() को कॉल करें, स्टार्ट-क्यूपीसी-वैल्यू घटाएं, क्यूपीएफ द्वारा सेकेंड (डबल में स्टोर) प्राप्त करने के लिए विभाजित करें, स्टार्टअप और प्रिंट पर सिस्टम समय के साथ इस मान को गठबंधन करें।

0
typedef struct _TIME_FIELDS { 

USHORT Year; USHORT Month; USHORT Day; USHORT Hour; USHORT Minute; USHORT Second; USHORT Milliseconds; USHORT Weekday; 

} TIME_FIELDS; 

typedef signed __int64  INT64; 
typedef unsigned __int64 UINT64; 


INT64 get_current_time() 
{ 
    ULONG secs; 
    LARGE_INTEGER tm; 

    KeQuerySystemTime (&tm); 

    RtlTimeToSecondsSince1970(&tm, &secs); 

    /* NOTE: tm is in 100s of nano seconds */ 
    return (secs * 1000 + (tm.QuadPart/10000)%1000); 
} 

LARGE_INTEGER get_system_time() 
{ 
    LARGE_INTEGER tm; 
    INT64 time = get_current_time(); 

    RtlSecondsSince1970ToTime (time, &tm); 

    /* NOTE: tm is in 100s of nano seconds */ 
    tm.QuadPart += (QTIME_MSECS(time)%1000)*10000; 
    return tm; 

} 

int log_current_time() 
{ 
    static char* month_names[] = 
    { 
    "Jan", 
    "Feb", 
    "Mar", 
    "Apr", 
    "May", 
    "Jun", 
    "Jul", 
    "Aug", 
    "Sep", 
    "Oct", 
    "Nov", 
    "Dec" 
    }; 

    LARGE_INTEGER tm, lcl_time; 
    TIME_FIELDS fields; 

    tm = get_system_time(); 

    ExSystemTimeToLocalTime (&tm, &lcl_time); 

    RtlTimeToTimeFields(&tm, &fields); 

    printf ("%s %02d %04d:%02d:%02d:%02d:%02d", month_names[fields.Month - 1], 
     fields.Day, fields.Year, fields.Hour, fields.Minute, fields.Second, 
     fileds.Milliseconds); 
} 

कृपया ध्यान दें कि यह कोड दो अनियंत्रित चीजें, TIME_FILEDS संरचना और RtlTimeToTimeFields फ़ंक्शन का उपयोग करता है। मैं अपने कोड में एक समान कार्यान्वयन का उपयोग कर रहा हूं और यह सभी मौजूदा विन एनटी स्वादों पर ठीक काम करता है। हालांकि, का उपयोग करते हुए इस गारंटी नहीं है अगले विन NT रिहाई के बीच पोर्टेबल

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