2013-08-20 11 views
10

मुझे पीडब्लूएम लहर के कर्तव्य चक्र में बदलाव के समय 1 स्तर के स्तर पर सटीक समय करने की आवश्यकता है।सटीक लिनक्स समय - घड़ी_gettime() के संकल्प को निर्धारित करता है?

पृष्ठभूमि

मैं एक Gumstix से अधिक जल कॉम उपयोग कर रहा हूँ (https://www.gumstix.com/store/app.php/products/265/) एक सिंगल कोर एआरएम कॉर्टेक्स ए 8 प्रोसेसर-499.92 BogoMIPS पर चल रहे है (Gumstix पृष्ठ 800Mhz साथ 1Ghz का दावा करता है अनुशंसित) के अनुसार/proc/cpuinfo। ओएस कर्नेल संस्करण 2.6.34 के आधार पर लिनक्स का एंगस्ट्रॉम छवि संस्करण है और यह गमस्टिक्स वाटर COM पर स्टॉक है।

समस्या

मैं लिनक्स में सटीक समय के बारे में पढ़ भी पर्याप्त मात्रा में किया है (और इसमें से अधिकांश की कोशिश की है) और आम सहमति है कि clock_gettime का उपयोग कर() और CLOCK_MONOTONIC संदर्भित सबसे अच्छा है लगता है ऐसा करने का तरीका (मुझे समय के लिए आरडीटीएससी रजिस्टर का उपयोग करना अच्छा लगेगा क्योंकि मेरे पास न्यूनतम पावर सेविंग क्षमताओं वाला एक कोर है लेकिन यह इंटेल प्रोसेसर नहीं है।) तो यहां अजीब हिस्सा है, जबकि clock_getres() 1 लौटाता है, 1 एनएस पर रिज़ॉल्यूशन का सुझाव देता है , वास्तविक समय परीक्षण 325768 किलोहर्ट्ज़ घड़ी टिकों के बीच वास्तव में 30517ns का न्यूनतम संकल्प सुझाता है (या यह संयोग नहीं हो सकता है)। यहाँ मैं क्या मतलब है:

gcc soExample.c -o runSOExample -lrt 

साथ भागो:

// Stackoverflow example 
#include <stdio.h> 
#include <time.h>  

#define SEC2NANOSEC 1000000000 

int main(int argc, const char* argv[]) 
{    
    // //////////////// Min resolution test ////////////////////// 
    struct timespec resStart, resEnd, ts; 
    ts.tv_sec = 0; // s 
    ts.tv_nsec = 1; // ns 
    int iters = 100; 
    double resTime,sum = 0;  
    int i; 
    for (i = 0; i<iters; i++) 
    { 
     clock_gettime(CLOCK_MONOTONIC, &resStart);  // start timer 
     // clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts); 
     clock_gettime(CLOCK_MONOTONIC, &resEnd);  // end timer 
     resTime = ((double)resEnd.tv_sec*SEC2NANOSEC + (double)resEnd.tv_nsec 
        - ((double)resStart.tv_sec*SEC2NANOSEC + (double)resStart.tv_nsec); 
     sum = sum + resTime; 
     printf("resTime = %f\n",resTime); 
    }  
    printf("Average = %f\n",sum/(double)iters); 
} 

संकलित साथ (डबल कास्टिंग से अधिक, tv_sec एक टाइम_टी में चिंता नहीं करें और tv_nsec एक लंबा है।):

./runSOExample 

नैनोस्लीप के साथ दिखाए गए अनुसार टिप्पणी की गई, परिणाम 0ns या 30517ns है जो बहुमत 0ns है। इससे मुझे विश्वास होता है कि CLOCK_MONOTONIC को 32.768kHz पर अपडेट किया गया है और अधिकांश घड़ी घड़ी को दूसरी घड़ी_gettime() कॉल से पहले अपडेट नहीं किया गया है और ऐसे मामलों में जहां परिणाम 30517ns है, कॉल को कॉल के बीच अपडेट किया गया है।

जब मैं अपने विकास कंप्यूटर (एएमडी एफएक्स (टीएम) -6100 छह-कोर प्रोसेसर 1.4 गीगाहर्ट्ज पर चल रहा हूं) पर एक ही चीज़ करता हूं तो न्यूनतम देरी 14 शून्य-151ns अधिक शून्य के साथ होती है।

तो, चलिए उन परिणामों की तुलना सीपीयू गति से करें। गमस्टिक्स के लिए, यह 30517ns (32.768kHz) 49 9.9 3 मेगाहट्र्ज सीपीयू के 15298 चक्रों के बराबर है। मेरे देव कंप्यूटर के लिए 150ns 1.4 गीगा सीपीयू के 210 चक्र के बराबर है।

clock_nanosleep() कॉल के साथ

uncommented औसत परिणाम ये हैं: Gumstix: औसत मूल्य = 213,623 और परिणाम भिन्न होता है, ऊपर और नीचे, 30517ns देव कंप्यूटर की कि न्यूनतम संकल्प के गुणकों द्वारा: साथ 57,710-68,065 एनएस कोई स्पष्ट प्रवृत्ति नहीं। देव कंप्यूटर के मामले में मैं उम्मीद करता हूं कि संकल्प वास्तव में 1 एनएस स्तर पर होगा और मापित ~ 150ns वास्तव में दो घड़ी_gettime() कॉल के बीच समाप्त हो गया है।

तो, मेरे प्रश्न ये हैं: न्यूनतम संकल्प क्या निर्धारित करता है? प्रो कंप्यूटर केवल ~ 2.6X तेज चल रहा है जब देव कंप्यूटर 30000X Gumstix से बेहतर क्यों है? क्या यह बदलने का कोई तरीका है कि कितनी बार CLOCK_MONOTONIC अद्यतन किया जाता है और कहां? कर्नेल में?

धन्यवाद! अगर आपको अधिक जानकारी या स्पष्टीकरण की आवश्यकता है तो पूछें।

+1

: लिनक्स कर्नेल कोड में, इन स्रोत फ़ाइलों और प्रलेखन के लिए देखो बस सोच रहा। सीपीयू घड़ी से चक्र पकड़ने के लिए कुछ प्रकार के हार्डवेयर की आवश्यकता नहीं होगी? कम से कम परिशुद्धता के उस स्तर पर। शायद गमस्टिक्स में ऐसा नहीं है? (मैं सिर्फ एक रजिस्टर के बारे में बात कर रहा हूं जो टिकों को गिन सकता है और रोलिंग से पहले उन्हें पकड़ सकता है।) – Jiminion

+0

आपके द्वारा किए गए सभी पढ़ने के साथ, आपने पहले ही देखा होगा *** [यह लिंक] (http: // gallinazo.flightgear.org/technology/gumstix-overo-rc-servos-and-pwm-signal-generation/)***, लेकिन किसी भी मामले में वैसे भी पोस्टिंग। कुछ सामग्री प्रासंगिक है। – ryyker

+0

एक ही समस्या होने के साथ। 30517ns के गुणक। मैं ओवरो टाइड का उपयोग कर रहा हूँ। क्या आपने कभी इस मुद्दे को हल किया है? – Ryan

उत्तर

1

मेरे पास हाथ पर गमस्टिक्स नहीं है, लेकिन ऐसा लगता है कि आपका क्लॉकसोर्स धीमा है। रन:

$ dmesg | grep clocksource

तो तुम वापस

[ 0.560455] Switching to clocksource 32k_counter

प्राप्त यह स्पष्ट करने वाले क्यों अपनी घड़ी इतनी धीमी गति से होता है।

हाल के कर्नेल में दो फाइलों के साथ /sys/devices/system/clocksource/clocksource0 निर्देशिका है: available_clocksource और current_clocksource। यदि आपके पास यह निर्देशिका है, तो दूसरे नाम में अपना नाम गूंजकर किसी दूसरे स्रोत पर स्विच करने का प्रयास करें।

7

जैसा कि मैं समझता हूं, दो वातावरण (गमस्टिक्स और आपके देव-कंप्यूटर) के बीच का अंतर अंतर्निहित टाइमर एच/डब्ल्यू हो सकता है जो वे उपयोग कर रहे हैं।

टिप्पणी की नैनोस्लीप() मामला:

आप उपयोग कर रहे हैं clock_gettime() दो बार। तुम क्या इस clock_gettime() अंत में (कर्नेल में) को मैप किया जाएगा का मोटा अनुमान देने के लिए: -)> clock_get (-

clock_gettime> posix_ktime_get_ts -> ktime_get_ts() -> timekeeping_get_ns() -> घड़ी-> पढ़ें()

घड़ी-> पढ़ें() मूल रूप से अंतर्निहित टाइमर ड्राइवर और संबंधित एच/डब्ल्यू द्वारा प्रदान किए गए काउंटर के मूल्य को पढ़ता है। पिछले और वर्तमान काउंटर वैल्यू में काउंटर के संग्रहीत मूल्य के साथ एक साधारण अंतर और फिर नैनोसेकंड रूपांतरण गणित आपको नैनोसेकंड को समाप्त कर देगा और कर्नेल में समय-समय पर डेटा संरचनाओं को अपडेट करेगा।

उदाहरण के लिए, यदि आपके पास एक एचपीईटी टाइमर है जो आपको 10 मेगाहट्र्ज घड़ी देता है, तो एच/डब्ल्यू काउंटर 100 एनएस समय अंतराल पर अपडेट हो जाएगा।

> पढ़ें(), आप एक्स के एक काउंटर मूल्य प्राप्त कहना चलें, पहले घड़ी- पर

लिनक्स समय ध्यान में रखते हुए डाटा संरचनाओं एक्स के इस मूल्य अंतर 'डी' कुछ की तुलना में पढ़ा जाएगा, मिल पुराना संग्रहीत काउंटर वैल्यू। कुछ काउंटर-फर्क 'डी' को नैनोसेकंड्स 'एन' रूपांतरण गणित में करें, 'n' द्वारा डेटा-स्ट्रक्चर अपडेट करें उपयोगकर्ता स्थान पर यह नया समय मान रखें।

जब दूसरी घड़ी-> पढ़ा() जारी किया जाता है, तो यह फिर से काउंटर को पढ़ेगा और समय अपडेट करेगा। अब, एक एचपीईटी टाइमर के लिए, यह काउंटर प्रत्येक 100ns को अपडेट कर रहा है और इसलिए, आप इस अंतर को उपयोगकर्ता-स्थान पर सूचित किए जायेंगे।

अब, इस एचपीईटी टाइमर को 32.768 किलोहर्ट्ज़ घड़ी धीमा कर दें। अब, घड़ी-> पढ़ें() का काउंटर केवल 30517 एनएस सेकेंड के बाद अपडेट किया जाएगा, इसलिए, यदि आप घड़ी_gettime() पर दूसरी कॉल इस अवधि से पहले हैं, तो आपको 0 (जो अधिकांश मामलों में है) मिलेगा और कुछ मामलों में , काउंटर के बढ़ने के बाद आपका दूसरा फ़ंक्शन कॉल रखा जाएगा, यानी 30517 एनएस समाप्त हो गया है। इसलिए, कभी-कभी 30517 एनएस का मूल्य।

uncommented नैनोस्लीप() मामला: के monotonic घड़ियों के लिए clock_nanosleep() का पता लगाने करते हैं:

clock_nanosleep() -> Nsleep -> common_nsleep() -> hrtimer_nanosleep() -> do_nanosleep()

do_nanosleep() केवल वर्तमान कार्य को INTERRUPTIBLE स्थिति में रखेगा, टाइमर समाप्त होने की प्रतीक्षा करेगा (जो 1 एनएस है) और उसके बाद वर्तमान कार्य को फिर से चलने वाले राज्य में सेट करें। आप देखते हैं, अब बहुत सारे कारक शामिल हैं, मुख्य रूप से जब आपका कर्नेल थ्रेड (और इसलिए उपयोगकर्ता स्थान प्रक्रिया) को फिर से निर्धारित किया जाएगा। आपके ओएस के आधार पर, जब आप एक संदर्भ-स्विच करते हैं तो आप हमेशा कुछ विलंबता का सामना करेंगे और यही वह है जो हम औसत मानों के साथ देखते हैं।

अब आपके प्रश्नों:

क्या न्यूनतम संकल्प है कि निर्धारित करता है?

मुझे लगता है कि आपके सिस्टम का संकल्प/परिशुद्धता अंतर्निहित टाइमर हार्डवेयर पर निर्भर करेगा (माना जाता है कि आपका ओएस उपयोगकर्ता अंतरिक्ष प्रक्रिया के लिए सटीकता प्रदान करने में सक्षम है)।

* प्रो कंप्यूटर केवल ~ 2.6X तेज चल रहा है जब देव कंप्यूटर 30000X गुमस्टिक से बेहतर क्यों है? *

क्षमा करें, मैंने आपको यहां याद किया। यह 30000x तेज कैसे है? मेरे लिए, यह 200x तेज (30714 एनएस/150 एनएस ~ 200 एक्स?) जैसा दिखता है। लेकिन वैसे भी, जैसा कि मैं समझता हूं, सीपीयू की गति टाइमर रिज़ॉल्यूशन/परिशुद्धता के साथ हो सकती है या नहीं। इसलिए, यह धारणा कुछ आर्किटेक्चर में सही हो सकती है (जब आप टीएससी एच/डब्ल्यू का उपयोग कर रहे हों), हालांकि, दूसरों में विफल हो सकता है (एचपीईटी, पीआईटी आदि का उपयोग कर)।

क्या यह बदलने का कोई तरीका है कि कितनी बार CLOCK_MONOTONIC अद्यतन किया जाता है और कहां? कर्नेल में?

आप विवरण के लिए हमेशा कर्नेल कोड देख सकते हैं (इस तरह मैंने इसे देखा है)।

  1. कर्नेल/POSIX-timers.c
  2. कर्नेल/hrtimer.c
  3. प्रलेखन/टाइमर/hrtimers.txt
संबंधित मुद्दे