2013-08-20 53 views
10

Tôi cần phải thực hiện thời gian chính xác đến mức 1 của chúng tôi để thay đổi chu kỳ nhiệm vụ của sóng pwm.Thời gian chính xác của Linux - Điều gì xác định độ phân giải của clock_gettime()?

nền

Tôi đang sử dụng một Gumstix trên mặt nước COM (https://www.gumstix.com/store/app.php/products/265/) mà có một bộ xử lý Cortex-A8 lõi ARM đơn chạy ở 499,92 bogomips (trang Gumstix tuyên bố lên đến 1Ghz với 800Mhz đề nghị) theo/proc/cpuinfo. Hệ điều hành là một phiên bản Angstrom Image của Linux dựa trên phiên bản hạt nhân 2.6.34 và nó là cổ phiếu trên Gumstix Water COM.

Vấn đề

tôi đã làm được một số tiền hợp lý của việc đọc về thời gian chính xác trong Linux (và đã cố gắng nhất của nó) và sự đồng thuận có vẻ là rằng việc sử dụng clock_gettime() và tham khảo CLOCK_MONOTONIC là tốt nhất cách để làm điều đó. (Tôi đã có thể sử dụng đăng ký RDTSC cho thời gian kể từ khi tôi có một lõi với khả năng tiết kiệm điện tối thiểu nhưng đây không phải là một bộ xử lý Intel.) Vì vậy, đây là phần lẻ, trong khi clock_getres() trả về 1, cho thấy độ phân giải 1 ns , các thử nghiệm tính thời gian thực tế cho thấy độ phân giải tối thiểu 30517ns hoặc (không thể trùng hợp) chính xác thời gian giữa các dấu tick đồng hồ 32.768KHz. Đây là những gì tôi muốn nói:

// 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); 
} 

(Đừng băn khoăn về việc chọn diễn viên đôi, tv_sec trong một time_t và tv_nsec là một chặng đường dài.)

Compile với:

gcc soExample.c -o runSOExample -lrt 

Run với:

./runSOExample 

Với nanosleep nhận xét như được hiển thị, kết quả là 0ns hoặc 30517ns với đa số là 0ns. Điều này khiến tôi tin rằng CLOCK_MONOTONIC được cập nhật ở mức 32.768kHz và hầu hết thời gian đồng hồ chưa được cập nhật trước khi cuộc gọi clock_gettime thứ hai() được thực hiện và trong trường hợp kết quả là 30517ns đồng hồ đã được cập nhật giữa các cuộc gọi.

Khi tôi làm điều tương tự trên máy tính phát triển của mình (AMD FX (tm) -6100 Bộ vi xử lý sáu lõi chạy ở tần số 1,4 GHz), độ trễ tối thiểu là 149-151ns liên tục không có số không.

Vì vậy, hãy so sánh các kết quả đó với tốc độ CPU. Đối với Gumstix, 30517ns (32.768kHz) tương đương với 15298 chu kỳ của CPU 499.93MHz. Đối với máy tính dev của tôi, 150ns tương đương với 210 chu kỳ của CPU 1,4Ghz.

Với clock_nanosleep() gọi uncomment kết quả trung bình là những: Gumstix: Giá trị trung bình = 213.623 và kết quả khác nhau, lên xuống, bởi bội số của độ phân giải tối thiểu của 30517ns máy tính Dev: 57.710-68.065 ns với không có xu hướng rõ ràng. Trong trường hợp của máy tính dev tôi mong đợi độ phân giải thực sự ở mức 1 ns và đo ~ 150ns thực sự là thời gian trôi qua giữa hai cuộc gọi clock_gettime().

Vì vậy, câu hỏi của tôi là: Điều gì xác định độ phân giải tối thiểu đó? Tại sao độ phân giải của máy tính dev 30000X tốt hơn so với Gumstix khi bộ xử lý chỉ chạy ~ 2.6X nhanh hơn? Có cách nào để thay đổi tần suất CLOCK_MONOTONIC được cập nhật và ở đâu không? Trong hạt nhân?

Cảm ơn! Nếu bạn cần thêm thông tin hoặc làm rõ chỉ cần hỏi.

+1

Chỉ cần tự hỏi. Sẽ không phải loại phần cứng nào cần thiết để lấy chu trình từ đồng hồ CPU? Ít nhất ở mức độ chính xác đó. Có lẽ Gumstix không có? (Tôi chỉ nói về một thanh ghi có thể đếm ve và giữ chúng trước khi lăn qua.) – Jiminion

+0

Với tất cả các bài đọc bạn nói bạn đã làm, bạn có thể đã thấy *** [liên kết này] (http: // gallinazo.flightgear.org/technology/gumstix-overo-rc-servos-and-pwm-signal-generation/)*** nhưng vẫn đăng bài trong trường hợp. Một số tài liệu có liên quan. – ryyker

+0

Có cùng một vấn đề chính xác. Số lượng 30517ns. Im sử dụng một thủy triều Overo. Bạn đã từng giải quyết vấn đề này chưa? – Ryan

Trả lời

1

Tôi không có kẹo cao su trên tay, nhưng có vẻ như đồng hồ của bạn bị chậm. chạy:

$ dmesg | grep clocksource

Nếu bạn nhận được trở lại

[ 0.560455] Switching to clocksource 32k_counter

Điều này có thể giải thích tại sao đồng hồ của bạn như vậy là chậm.

Trong các hạt gần đây có một thư mục /sys/devices/system/clocksource/clocksource0 với hai tệp: available_clocksourcecurrent_clocksource. Nếu bạn có thư mục này, hãy thử chuyển sang một nguồn khác bằng cách lặp lại tên của nó thành tệp thứ hai.

7

Như tôi đã hiểu, sự khác biệt giữa hai môi trường (Gumstix và Dev-computer) có thể là bộ đếm thời gian cơ bản mà chúng đang sử dụng.

nhận xét nanosleep() trường hợp:

Bạn đang sử dụng clock_gettime() hai lần. Để cung cấp cho bạn ý tưởng sơ bộ về những gì clock_gettime() cuối cùng sẽ được ánh xạ tới (trong hạt nhân):

clock_gettime -> clock_get() -> posix_ktime_get_ts -> ktime_get_ts() -> timekeeping_get_ns() -> clock-> read()

clock-> read() về cơ bản đọc giá trị của bộ đếm được cung cấp bởi trình điều khiển bộ định thời cơ sở và h/w tương ứng. Một sự khác biệt đơn giản với giá trị được lưu trữ của bộ đếm trong quá khứ và giá trị bộ đếm hiện tại và sau đó tính toán chuyển đổi nano giây sẽ mang lại cho bạn nano giây trôi qua và sẽ cập nhật cấu trúc dữ liệu theo thời gian trong hạt nhân.

Ví dụ: nếu bạn có bộ hẹn giờ HPET cung cấp cho bạn đồng hồ 10 MHz, bộ đếm h/w sẽ được cập nhật ở khoảng thời gian 100 ns.

phép nói rằng, trên Clock- đầu tiên> read(), bạn nhận được một giá trị truy cập của X.

Thời gian lưu giữ Linux cấu trúc dữ liệu sẽ đọc giá trị này của X, có sự khác biệt 'D'so với một số giá trị truy cập được lưu trữ cũ.Do một số khác biệt 'D' đối với toán học chuyển đổi nano giây, cập nhật cấu trúc dữ liệu theo 'n' Sử dụng giá trị thời gian mới này cho không gian người dùng.

Khi đồng hồ thứ hai-> đọc() được phát hành, nó sẽ đọc lại bộ đếm và cập nhật thời gian. Bây giờ, đối với bộ hẹn giờ HPET, bộ đếm này được cập nhật mỗi 100ns và do đó, bạn sẽ thấy sự khác biệt này được báo cáo cho không gian người dùng.

Bây giờ, hãy thay bộ hẹn giờ HPET này bằng đồng hồ chậm 32.768 KHz. Bây giờ, clock-> read() 's counter sẽ cập nhật chỉ sau 30517 ns giây, vì vậy, nếu bạn gọi thứ hai tới clock_gettime() trước giai đoạn này, bạn sẽ nhận được 0 (phần lớn các trường hợp) và trong một số trường hợp , cuộc gọi hàm thứ hai của bạn sẽ được đặt sau khi bộ đếm đã tăng lên 1, tức là 30517 ns đã trôi qua. Do đó, giá trị của 30517 ns đôi khi.

không chú thích nanosleep() trường hợp: Hãy theo dõi các clock_nanosleep() cho đồng hồ đơn điệu:

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

do_nanosleep() sẽ chỉ cần đặt tác vụ hiện tại ở trạng thái TƯƠNG LAI, sẽ đợi bộ hẹn giờ hết hạn (là 1 ns) và sau đó đặt lại tác vụ hiện tại ở trạng thái RUNNING. Bạn thấy đấy, có rất nhiều yếu tố liên quan đến bây giờ, chủ yếu là khi chuỗi hạt nhân của bạn (và do đó quá trình không gian người dùng) sẽ được lên lịch lại. Tùy thuộc vào hệ điều hành của bạn, bạn sẽ luôn phải đối mặt với một số độ trễ khi bạn thực hiện chuyển ngữ cảnh và đây là những gì chúng tôi quan sát với các giá trị trung bình.

Bây giờ Câu hỏi của bạn:

Điều gì xác định độ phân giải tối thiểu đó?

Tôi nghĩ độ phân giải/độ chính xác của hệ thống sẽ phụ thuộc vào phần cứng hẹn giờ bên dưới được sử dụng (giả sử HĐH của bạn có thể cung cấp độ chính xác cho quy trình không gian của người dùng).

* Tại sao độ phân giải của máy tính dev 30000X tốt hơn so với Gumstix khi bộ xử lý chỉ chạy ~ 2.6X nhanh hơn? *

Xin lỗi, tôi nhớ bạn ở đây. Làm thế nào nó là 30000x nhanh hơn? Đối với tôi, nó trông giống như một cái gì đó 200x nhanh hơn (30714 ns/150 ns ~ 200X?). Nhưng dù sao, như tôi hiểu, tốc độ CPU có thể hoặc có thể không phải làm với độ phân giải/độ chính xác hẹn giờ. Vì vậy, giả định này có thể đúng trong một số kiến ​​trúc (khi bạn đang sử dụng TSC H/W), mặc dù, có thể thất bại ở những người khác (sử dụng HPET, PIT, v.v.).

Có cách nào thay đổi tần suất CLOCK_MONOTONIC được cập nhật và ở đâu không? Trong hạt nhân?

bạn luôn có thể xem mã hạt nhân để biết chi tiết (đó là cách tôi nhìn vào nó). Trong mã hạt nhân Linux, tìm kiếm những tập tin nguồn và Tài liệu:

  1. kernel/posix-timers.c
  2. kernel/hrtimer.c
  3. tài liệu/giờ/hrtimers.txt
Các vấn đề liên quan