Có cách nào để có được CLOCK_TAI chính xác trên Linux không?


8

Máy Linux của tôi hỗ trợ CLOCK_TAI, nhưng phần bù của nó CLOCK_REALTIMEkhông chính xác bằng 0 (đây là mặc định). Có phần mềm hoặc giải pháp nào khác sẽ duy trì CLOCK_TAInhư TAI không?

Từ câu trả lời ở đâyở đây , dường như không phải ntpdcũng không chronydlàm điều này.

Tôi rất vui khi đặt đồng hồ phần cứng của mình thành TAI để đạt được điều này, được cung cấp CLOCK_REALTIMEgettimeofdayvv trả lại thời gian POSIX (về cơ bản là UTC).

Câu trả lời:


4

Tôi nghĩ rằng bạn muốn clock_gettimeCLOCK_TAIđể làm việc đúng cách. Tôi cũng vậy.

Câu quan trọng trong câu trả lời được tham chiếu là: "Xin lưu ý rằng phần bù từ CLOCK_REALTIME được khởi tạo khi khởi động về 0 và cả ntpd và chronyd đều không đặt nó theo giá trị đúng (hiện tại là 35)."

Điều này có thể vẫn đúng, ngoài phần bù bây giờ là 37, nhưng ít nhất một ntpd gần đây có thể được cấu hình để đặt phần bù. Tôi đã làm như sau trên một máy openSUSE:

vi /etc/ntp.conf # Add the line: leapfile /var/lib/ntp/etc/ntp.leapseconds
update-leap
service ntpd restart
less /var/log/ntp # Check for errors

Sau đó clock_gettime(CLOCK_TAI, &res)dường như hoạt động chính xác.

Tôi nghĩ rằng ntp thiết lập bù sử dụng ntp_adjtimevới MOD_TAI. Tìm kiếm nguồn chrony grep -P '(ADJ|MOD)_TAI'mà không tìm thấy kết quả trùng khớp, vì vậy có vẻ như chrony chưa có khả năng này.


3

Bạn có thể sử dụng libtaitừ djb: https://cr.yp.to/libtai.html

Nó là gì?

libtai là một thư viện để lưu trữ và thao tác ngày và thời gian.

libtai hỗ trợ hai thang đo thời gian: (1) TAI64, bao phủ vài trăm tỷ năm với độ chính xác 1 giây; (2) TAI64NA, bao phủ cùng kỳ với độ chính xác 1-giây. Cả hai thang đo đều được định nghĩa theo TAI, tiêu chuẩn thời gian thực quốc tế hiện tại.

libtai cung cấp một định dạng nội bộ cho TAI64, struct tai, được thiết kế để thao tác thời gian nhanh. Các thường trình tai_pack () và tai_unpack () chuyển đổi giữa struct tai và định dạng lưu trữ TAI64 8 byte di động. libtai cung cấp các định dạng bên trong và bên ngoài tương tự cho TAI64NA.

libtai cung cấp caldate struct để lưu trữ ngày ở dạng năm tháng. Nó có thể chuyển đổi caldate struct, theo lịch Gregorian, sang số ngày Julian được sửa đổi để số học ngày dễ dàng.

libtai cung cấp cấu trúc caltime để lưu trữ ngày và thời gian theo lịch cùng với các lần bù UTC. Nó có thể chuyển đổi từ struct tai sang struct caltime trong UTC, chiếm vài giây nhuận, để hiển thị ngày giờ chính xác. Nó cũng có thể chuyển đổi trở lại từ struct caltime sang struct tai cho đầu vào của người dùng. Tốc độ chuyển đổi UTC-TAI tổng thể của nó tốt hơn 100 lần so với triển khai UNIX mktime () thông thường.

Phiên bản libtai này yêu cầu một hệ thống UNIX với gettimeofday (). Sẽ dễ dàng chuyển sang các hệ điều hành khác với trình biên dịch hỗ trợ số học 64 bit.

Mã nguồn libtai nằm trong miền công cộng.


Tôi nghĩ rằng đây chỉ là một thư viện để chuyển đổi định dạng thời gian. Tôi đang tìm kiếm một chương trình sẽ điều chỉnh đồng hồ Linux.
Ashley Yakeley

Tiêu đề câu hỏi của bạn cho biết "nhận TAI" không có nghĩa là "sử dụng TAI cho đồng hồ của tôi" hoặc "đặt hệ thống thành TAI." Khi bạn đề cập đến việc đặt đồng hồ thành TAI trong cơ thể, có vẻ như bạn có thể tuân theo tùy chọn này nếu nó cho phép bạn "lấy TAI chính xác từ hệ thống".
dfc

Tôi đang hỏi về đồng hồ Linux CLOCK_TAI.
Ashley Yakeley

3

Khi tôi đang chạy chronythay vì cũ ntpd, tôi không có cách tự động để có được tham số kernel đúng, vì vậy tôi đã xem xét một giải pháp thay thế.

Vì độ lệch giữa TAI và UTC tương đối ổn định (thay đổi <một lần mỗi năm), có thể đặt tĩnh tham số kernel, sau đó sử dụng đồng hồ CLOCK_TAI trong một ứng dụng sẽ cho giá trị chính xác.

Có một ứng dụng thử nghiệm để thiết lập bù kernel trong các nguồn kernel, trong tools/testing/selftests/timers/set-tai.c. Và, giả sử bạn đã tzdatacài đặt gói, có một tệp có phần bù giữa UTC và TAI /usr/share/zoneinfo/leap-seconds.list.

Tôi đã cắt nhỏ ứng dụng kiểm tra kernel để chính trở thành:

int main(int argc, char **argv)
{
    int i, ret;

    ret = get_tai();
    printf("tai offset started at %i\n", ret);

    if (argc < 2)
    {
        printf("New offset not given, not setting\n");
    }
    else
    {
        i = strtol(argv[1],NULL,10);
        printf("Attempting to set TAI offset to %d\n",i);
        printf("Checking tai offsets can be properly set: ");
        ret = set_tai(i);
        ret = get_tai();
        if (ret != i) {
            printf("[FAILED] expected: %i got %i\n", i, ret);
            return EXIT_FAILURE;
        }
    }
    printf("[OK]\n");
    return EXIT_SUCCESS;
}

Sau đó, đối với trường hợp sử dụng của tôi, đó chỉ là vấn đề trích xuất giá trị chính xác từ leap-seconds.listtệp và chạy set-taivới giá trị này như một tham số ( /etc/rc.localđể làm cho nó xảy ra khi khởi động). Một ví dụ về cách làm này là:

TAI_OFFSET=$(grep -v '^#' /usr/share/zoneinfo/leap-seconds.list | tail -1 | awk '{ print $2 }')
if [ -x /usr/local/sbin/set-tai ]; then
  /usr/local/sbin/set-tai $TAI_OFFSET
fi

Hy vọng điều này hữu ích cho người khác!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.