2016-10-08 23 views
7

Tôi có một số mã cố gắng xác định thời gian thực hiện của một khối mã.Độ chính xác của hàm clock() trong C

#include <time.h> 
#include <stdio.h> 

int main() 
{ 
    clock_t start_t, end_t, total_t; 
    int i; 

    start_t = clock(); //clock start 
    printf("Starting of the program, start_t = %ld\n", start_t); 

    printf("Going to scan a big loop, start_t = %ld\n", start_t); 
    for(i=0; i< 10000000; i++) //trying to determine execution time of this block 
    { 
    } 
    end_t = clock(); //clock stopped 
    printf("End of the big loop, end_t = %ld\n", end_t); 

    total_t = (long int)(end_t - start_t); 
    printf("Total time taken by CPU: %lu\n", total_t ); 

    return(0); 
} 

Kết quả của đoạn mã trên máy tính của tôi là

Starting of the program, start_t = 8965 
Going to scan a big loop, start_t = 8965 
End of the big loop, end_t = 27259 
Total time taken by CPU: 18294 

Vì vậy, nếu CPU của tôi đã chạy ở 21 MHz và giả định rằng đây là điều duy nhất nhận được thực hiện, mỗi chu kỳ máy sẽ là xấp xỉ bằng 47 nano giây (18294 * 47) = 859818 nano giây.

Đây có phải là thời gian thực hiện cho vòng lặp for trong mã của tôi không? Tôi có đưa ra một số giả định không chính xác ở đây không.

+0

Để có thời gian tính bằng giây, bạn nên chia số, ví dụ 'total_t' trong trường hợp của bạn, với' CLOCKS_PER_SEC'. Lưu ý rằng bạn cần truyền 'total_t' vào một giá trị dấu chấm động để nó hoạt động. –

+1

Cũng là một sự đánh dấu nhỏ trên lược đồ đặt tên của bạn: Các biểu tượng kết thúc bằng hậu tố '_t' thường được sử dụng cho các loại bí danh (như được tạo bằng' typdef'). Ví dụ 'size_t' hoặc' time_t' và thậm chí 'clock_t'. –

+0

@JoachimPileborg Tôi đã xem lại tài liệu cho hàm clock() và CLOCK_PER_SEC sẽ trả về thời gian chính xác tối đa 1/100 giây và tôi đang tìm kiếm độ phân giải tối đa 10 micro giây vì vậy tôi đã sử dụng cách tiếp cận được đề cập. Ngoài ra tôi muốn điều này làm việc trên các nền tảng và kiến ​​trúc khác nhau nên tôi nghĩ rằng chỉ cần tính toán sự khác biệt và sau đó nhân với tốc độ đồng hồ sẽ là một lựa chọn tốt hơn vì CLOCKS_PER_SEC sẽ thay đổi với kiến ​​trúc. – user2808264

Trả lời

4

Đơn vị thời gian được sử dụng bởi hàm clock là tùy ý. Trên hầu hết các nền tảng, nó không liên quan đến tốc độ xử lý. Nó thường liên quan đến tần số của một ngắt hẹn giờ bên ngoài - có thể được cấu hình trong phần mềm - hoặc một giá trị lịch sử được giữ cho khả năng tương thích qua nhiều năm tiến hóa của bộ vi xử lý. Bạn cần sử dụng macro CLOCKS_PER_SEC để chuyển đổi thành thời gian thực.

printf("Total time taken by CPU: %fs\n", (double)total_t/CLOCKS_PER_SEC); 

Thư viện chuẩn C được thiết kế để có thể triển khai trên nhiều phần cứng, bao gồm bộ vi xử lý không có bộ đếm thời gian bên trong và dựa vào thiết bị ngoại vi. Nhiều nền tảng có cách chính xác hơn để đo thời gian đồng hồ treo tường hơn time và các cách chính xác hơn để đo mức tiêu thụ CPU hơn clock. Ví dụ: trên các hệ thống POSIX (ví dụ: Linux và các hệ thống giống Unix khác), bạn có thể sử dụng getrusage, có độ chính xác micro giây.

struct timeval start, end; 
struct rusage usage; 
getrusage(RUSAGE_SELF, &usage); 
start = usage.ru_utime; 
… 
getrusage(RUSAGE_SELF, &usage); 
end = usage.ru_utime; 
printf("Total time taken by CPU: %fs\n", (double)(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec)/1e-6); 

Nếu có, clock_gettime(CLOCK_THREAD_CPUTIME_ID) hoặc clock_gettime(CLOCK_PROCESS_CPUTIME_ID) có thể cho độ chính xác cao hơn. Nó có độ chính xác nano giây.

Lưu ý sự khác biệt giữa độ chính xác và độ chính xác: độ chính xác là đơn vị mà giá trị được báo cáo. Độ chính xác là cách các giá trị được báo cáo gần với giá trị thực. Trừ khi bạn đang làm việc trên một số real-time system, không có đảm bảo nào về độ dài của một đoạn mã, bao gồm cả việc tự gọi các hàm đo.

Một số bộ xử lý có chu kỳ đồng hồ đếm chu kỳ bộ xử lý thay vì đồng hồ treo tường, nhưng điều này sẽ rất cụ thể cho từng hệ thống.

Bất cứ khi nào tạo điểm chuẩn, hãy cẩn thận rằng những gì bạn đang đo là thực thi thực thi cụ thể này trên CPU cụ thể này trong những trường hợp cụ thể này và kết quả có thể hoặc không thể khái quát hóa với các tình huống khác. Ví dụ, vòng lặp trống trong câu hỏi của bạn sẽ được tối ưu hóa bởi hầu hết các trình biên dịch trừ khi bạn tắt tối ưu hóa. Đo tốc độ của mã unoptimized thường là vô nghĩa. Ngay cả khi bạn thêm công việc thực sự vào vòng lặp, hãy cẩn thận với các tiêu chuẩn đồ chơi: chúng thường không có các đặc tính hiệu suất giống như mã thực tế. Trên các CPU cao cấp hiện đại như PC và điện thoại thông minh, các tiêu chuẩn của mã chuyên sâu CPU thường rất nhạy cảm với hiệu ứng bộ nhớ đệm và kết quả có thể phụ thuộc vào những gì khác đang chạy trên hệ thống, trên mô hình CPU chính xác (do khác nhau kích thước bộ nhớ cache và bố trí), trên địa chỉ mà tại đó mã sẽ xảy ra được tải, v.v.

+0

@Giles Đây chính xác là những gì tôi cần. Nó có độ phân giải tối đa 1 chúng tôi so với chức năng đồng hồ có độ phân giải 100 ms. Nhưng bạn có biết mã này có thể di chuyển hay không. Tôi cần điều này để chạy trên một hệ thống ARM M0. Có cách nào tôi có thể làm cho mã này di động? – user2808264

+0

@ user2808264 Nếu bạn cần một cái gì đó vượt quá 'đồng hồ' thì nó sẽ không được di động, bạn sẽ tạo ra một sự phụ thuộc vào hệ điều hành hoặc CPU hoặc cả hai. Kiểm tra những gì hệ điều hành của bạn cung cấp. Nếu bạn đang chạy trên kim loại trần, nếu bạn muốn độ chính xác gần 1µs thì bạn sẽ cần một bộ đếm chu kỳ chính xác, kiểm tra chức năng gỡ lỗi nào hiện diện trên CPU của bạn (tôi nghĩ đó là tính năng tùy chọn). Nếu bạn không cần độ chính xác đó nhiều thì bạn có thể sử dụng [systick timer] (http://sushihangover.github.io/cortex-m-systick-polling-vs-interrupts/) tùy chọn nhưng phổ biến rộng rãi. – Gilles

Các vấn đề liên quan