2014-09-29 28 views
0

我有一個循環運行每個X usecs,其中包括做一些I/O然後睡覺剩餘的X usecs。以(大致)計算出的睡眠時間,所有我做的是一個時間戳之前和之後的I/O和減去X.這裏的區別是我使用時間戳功能:使用gettimeofday()自我糾正定期計時器()

long long getus() 
{ 
     struct timeval time; 
     gettimeofday(&time, NULL); 
     return (long long) (time.tv_sec + time.tv_usec); 
} 

正如你可以想象的那樣,這開始漂移很快,I/O突發之間的實際時間通常比X多幾毫秒。爲了讓它更準確一點,我想也許如果我保留一條記錄以前的開始時間戳,每當我開始一個新的週期時,我可以計算上一個週期花費多長時間(從這個開始時間戳到前一個週期之間的時間)。然後,我知道它比X多了多久,並且我可以修改我的睡眠來補償這個週期。

這裏是我正在努力實現它:

long long start, finish, offset, previous, remaining_usecs; 
    long long delaytime_us = 1000000; 

    /* Initialise previous timestamp as 1000000us ago*/ 
    previous = getus() - delaytime_us; 
    while(1) 
    { 
      /* starting timestamp */ 
      start = getus(); 

      /* here is where I would do some I/O */ 

      /* calculate how much to compensate */ 
      offset = (start - previous) - delaytime_us; 

      printf("(%lld - %lld) - %lld = %lld\n", 
        start, previous, delaytime_us, offset); 

      previous = start; 

      finish = getus(); 

      /* calculate to our best ability how long we spent on I/O. 
      * We'll try and compensate for its inaccuracy next time around!*/ 
      remaining_usecs = (delaytime_us - (finish - start)) - offset; 

      printf("start=%lld,finish=%lld,offset=%lld,previous=%lld\nsleeping for %lld\n", 
        start, finish, offset, previous, remaining_usecs); 

      usleep(remaining_usecs); 

    } 

這似乎在循環的第一次迭代工作,但是之後的事情搞的一團糟。

下面是5次迭代循環的輸出:

(1412452353 - 1411452348) - 1000000 = 5 
start=1412452353,finish=1412458706,offset=5,previous=1412452353 
sleeping for 993642 

(1412454788 - 1412452353) - 1000000 = -997565 
start=1412454788,finish=1412460652,offset=-997565,previous=1412454788 
sleeping for 1991701 

(1412454622 - 1412454788) - 1000000 = -1000166 
start=1412454622,finish=1412460562,offset=-1000166,previous=1412454622 
sleeping for 1994226 

(1412457040 - 1412454622) - 1000000 = -997582 
start=1412457040,finish=1412465861,offset=-997582,previous=1412457040 
sleeping for 1988761 

(1412457623 - 1412457040) - 1000000 = -999417 
start=1412457623,finish=1412463533,offset=-999417,previous=1412457623 
sleeping for 1993507 

輸出的第一行顯示前一個週期的時間是如何計算的。看起來前兩個時間戳基本上是1000000us(1412452353 - 1411452348 = 1000005)。然而在此之後,開始時間戳之間的距離開始看起來不那麼合理,以及偏移量。 有誰知道我在這裏做錯了嗎?

編輯:我也歡迎有更好的方法獲得準確的計時器的建議,並在延遲期間能夠睡覺 !

回答

0

經過一些更多的研究,我發現這裏有兩個錯誤 - 首先,我計算錯誤的時間戳。 getus()應該返回這樣的:

return (long long)1000000 *(time.tv_sec + time.tv_usec);

其次,我要存儲時間戳unsigned long longuint64_t。 所以getus()應該是這樣的:

uint64_t getus() 
{ 
     struct timeval time; 
     gettimeofday(&time, NULL); 
     return (uint64_t) 1000000 * (time.tv_sec + time.tv_usec); 
} 

我不會真的能夠測試,直到明天,所以我會報到。