Cách tốt nhất để có được thời gian trôi qua tính bằng milisecond trong windows


8

Tôi đang cố gắng thực hiện bằng cách sử dụng hai PHIM, chuyển chúng thành ULONGLONG, trừ các ULONGLONG và chia kết quả cho 10000. Nhưng nó khá chậm và tôi muốn biết liệu có cách nào tốt hơn không. Tôi sử dụng c ++ với phiên bản visual studio 2008 express. Đây là những gì tôi đang sử dụng:

FILETIME filetime,filetime2;
GetSystemTimeAsFileTime(&filetime);
Sleep(100);
GetSystemTimeAsFileTime(&filetime2);
ULONGLONG time1,time2;
time1 = (((ULONGLONG) filetime.dwHighDateTime) << 32) + filetime.dwLowDateTime;
time2 = (((ULONGLONG) filetime2.dwHighDateTime) << 32) + filetime2.dwLowDateTime;
printf("ELAPSED TIME IN MS:%d",(int)((time2-time1)/10000));

Câu trả lời:


11

Sử dụng QueryPerformanceCorer .

long long milliseconds_now() {
    static LARGE_INTEGER s_frequency;
    static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
    if (s_use_qpc) {
        LARGE_INTEGER now;
        QueryPerformanceCounter(&now);
        return (1000LL * now.QuadPart) / s_frequency.QuadPart;
    } else {
        return GetTickCount();
    }
}

// Somewhere else...
    // ...
    long long start = milliseconds_now();
    // ....
    long long elapsed = milliseconds_now() - start;

Và điều đó sẽ chạy nhanh?
XaitormanX

Đủ nhanh để gọi hàng chục lần trong một khung hình mà không có tác động đáng chú ý. Bao nhiêu lần bạn mong muốn cần nó?

khoảng 4 lần một khung hình. Nhưng nếu tôi đặt mã đó vào một vòng lặp để thực hiện 100 lần, thì sẽ mất khoảng 10 giây để thực thi, điều này chậm, tại sao điều này lại xảy ra?
XaitormanX

1
Bạn có một Sleep(100)trong mã của bạn. Nó không có gì để làm với bộ tính giờ.

2
Nó chạy nhanh trên p90 vào năm 1996; Tôi nghĩ rằng nó sẽ chạy đủ nhanh ngày hôm nay. ;)
Maximus Minimus

7

Nói chung timeGetTime () là tốt nhất cho logic trò chơi thời gian - GetTickCount không có độ phân giải khá cao và QPC & RDTSC gặp nhiều rắc rối hơn so với giá trị của mục đích đó.

Mặt khác, để định hình, RDTSC hoặc QPC có thể khá đáng giá. Tôi thích RDTSC hơn QPC, mặc dù microsoft khuyến nghị QPC.

Bốn chức năng thời gian phổ biến tôi sử dụng trên win32:

GetTickCount () trả về thời gian hiện tại tính bằng mili giây so với số không tùy ý (thông thường, mặc dù không phải lúc nào cũng là thời gian khởi động hệ thống), dưới dạng số nguyên 32 bit (do đó, nó sẽ kết thúc sau mỗi 49 ngày hoặc lâu hơn). Nó thường là phương pháp nhanh nhất để đo thời gian. Thật không may, nó có độ phân giải thấp - thông thường nó chỉ cập nhật 64 lần mỗi giây. Trái với tin đồn phổ biến, việc gọi timeBeginPeriod (1) sẽ không tăng độ phân giải trên bất kỳ hệ thống nào tôi đã thử nghiệm trên đó. Ngoài ra còn có một biến thể 64 bit nếu bạn lo lắng về nó.

timeGetTime () trả về thời gian hiện tại tính bằng mili giây so với một số 0 tùy ý, dưới dạng giá trị 32 bit (do đó, nó sẽ kết thúc sau 49 ngày hoặc lâu hơn). Nó không nhanh như GetTickCount, nhưng vẫn khá hợp lý. Nó có thể chính xác đến một mili giây, mặc dù điều đó có thể yêu cầu gọi timeBeginPeriod (1) trước. Sử dụng timeGetTime yêu cầu liên kết với winmm.lib và bao gồm Mmsystem.h.

QueryPerformanceCorer () trả về thời gian hiện tại theo các đơn vị tùy ý dưới dạng số nguyên 64 bit. Bạn có thể tìm ra các đơn vị là gì bằng cách gọi QueryPerformanceFrequency () và các đơn vị sẽ không thay đổi (vắng mặt khi khởi động lại). Việc triển khai cơ bản của điều này rất khác nhau và mỗi lần thực hiện đều có những lỗi và lỗi riêng có thể xảy ra trên một số phần cứng, khiến việc này trở nên đáng ghét khi sử dụng trong các ứng dụng được triển khai rộng rãi. Một số triển khai rất chậm, một số khác thì hợp lý, mặc dù không triển khai nhanh như GetTickCount hoặc thậm chí timeGetTime. Thông thường độ phân giải thời gian tốt hơn 1 micro giây, mặc dù không nhất thiết phải tốt hơn nhiều.

RDTSC là một opcode ngôn ngữ lắp ráp x86 / x64 trả về thời gian hiện tại theo đơn vị chu kỳ CPU (nghĩa là số nguyên 64 bit. Trên một số trình biên dịch, nó có thể được truy cập dưới dạng nội tại (__rdstc), trên các trình biên dịch khác, bạn sẽ cần mã asm nội tuyến. Tốc độ của nó thay đổi một chút giữa các CPU nhưng thường khá hợp lý - thường nhanh hơn đáng kể so với QueryPerformanceCorer nhưng không nhanh bằng GetTickCount. Đôi khi, nó có thể chạy ngược trên CPU đa lõi khi bạn chuyển đổi lõi do đồng bộ hóa không hoàn hảo giữa các lõi, các đơn vị rất khó để tìm ra và các đơn vị có thể thay đổi trong thời gian giữa do quản lý năng lượng thay đổi tốc độ của xung nhịp CPU.

Lưu ý rằng mỗi phương thức trong số bốn phương pháp này có thể trôi tương đối so với ba phương pháp kia - không có dòng chảy thời gian có thẩm quyền rõ ràng.


3

Để trả lời câu hỏi của bạn: không có giải pháp "tốt nhất" để đo thời gian. Mỗi phương pháp đều có ưu điểm / nhược điểm riêng. Tất cả phụ thuộc vào nhu cầu của bạn.

Dưới đây là một số câu hỏi bạn nên tự hỏi mình trước khi chọn một giải pháp:

  • độ phân giải hẹn giờ . Bạn có thực sự cần một bộ đếm thời gian chính xác (<1ms) hoặc bạn có thể sống với một cái gì đó kém chính xác hơn (ví dụ: độ chính xác 10ms)?

  • chi phí cpu . một số phương pháp sẽ yêu cầu nhiều cpu hơn một số phương pháp khác. nói chung bộ định thời chính xác hơn đòi hỏi nhiều cpu hơn. Ngoài ra, việc gọi một số phương thức có thể gây hậu quả cho các ứng dụng khác (ví dụ: gọi timeBeginPeriod(1)win32 làm căng thẳng hệ điều hành và giảm tuổi thọ pin máy tính xách tay)

  • làm việc với SMP . một số phương pháp sử dụng dữ liệu CPU cụ thể (ví dụ: số chu kỳ đã trôi qua) và có thể gặp một số vấn đề trong môi trường đa bộ xử lý.

  • hoạt động với CPU có tính năng tiết kiệm năng lượng. Một số cpu có khả năng thay đổi tần số theo thời gian, điều này có thể gây ra một số rắc rối cho một số phương pháp thời gian.

Đối với ví dụ bạn đưa ra, tôi sẽ sử dụng kết hợp QueryPerformanceCounter() / QueryPerformanceFrequency().

Ngoài ra, xin lưu ý rằng trong ví dụ bạn đưa ra sleep(100)thực sự có thể đợi hơn 100ms. Vì vậy, ngay cả với bộ đếm thời gian rất chính xác, nó có thể trả về một số kết quả khác ngoài 100ms.


Mặc dù đúng là một số phương pháp thời gian có vấn đề trên SMP, đây luôn là những lỗi trong HAL, BIOS hoặc các vấn đề khác liên quan đến trình điều khiển và phải được khắc phục ở cấp độ đó. Thật hiếm khi bạn có thể giải quyết vấn đề bằng cách chuyển sang một phương pháp thời gian khác. Ví dụ, tôi đã thấy QPC chạy ngược lại vì các trình điều khiển xấu, nhưng GetTickCount cũng vậy - lý do duy nhất không phải là vì cú nhảy là ~ 50 tiếng, vì vậy nó không nhận thấy điều đó. Tốt nhất, ứng dụng của bạn có thể thực hiện maxcuộc gọi với giá trị được trả về trước đó.

Do đó, QPC và các chức năng tương đương trên các HĐH khác như POSIX clock_gettime, tất cả đều được chỉ định để không chạy ngược lại ngay cả trên các hệ thống SMP và không phụ thuộc vào tần số CPU hiện tại. Vì vậy, đó là lời khuyên tồi tệ để cảnh báo mọi người tránh xa họ và hướng tới các chức năng thời gian tồi tệ hơn, bởi vì bất kỳ chức năng thời gian nào khác cũng có thể gặp phải vấn đề tương tự nếu bạn có thể khiến họ làm việc chính xác như bạn muốn từ QPC ngay từ đầu. Vì vậy, yeah, có một giải pháp tốt nhất: QPC, clock_gettime, và mach_absolute_time. Đối với thời gian vòng lặp trò chơi, không có lý do để sử dụng bất cứ điều gì khác nếu chúng có sẵn.

0

Tôi mới thực hiện một số điểm chuẩn và không có nhiều lý do để sử dụng timeGetTime nữa. QueryPerformanceCorer nhanh hơn một chút và chính xác hơn nhiều.

Sau đó, có GetTickCount, gần như ngay lập tức, vì tất cả những gì nó làm là đọc lại một số giá trị mà HĐH thay đổi trong quá trình lập lịch trình. Giá trị giữ nguyên trong hơn 15ms tại một thời điểm và không được khuyến nghị cho bất cứ điều gì ngoài thời gian rất thô.


-1

Hãy xem hàm GetTickCount () giá trị trả về của nó là số mili giây đã trôi qua kể từ khi hệ thống được khởi động.

unsigned int Last = 0;
unsigned int Now = 0;
Last = GetTickCount();
//...Run your functions..
Now = GetTickCount();
printf("Elapsed Time in Milliseconds: %i",(Now-Last));

6
-1. GetTickCount () có độ phân giải kém.
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.