Làm thế nào để đo thời gian thực hiện trung bình của một kịch bản?


23

Tôi có hai kịch bản mà mỗi kịch bản tính giai thừa của một số. Tôi muốn biết cái nào nhanh hơn. Các timelệnh mang lại cho tôi mili giây và kết quả là khác nhau theo thời gian:

piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.089s
user    0m0.052s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.091s
user    0m0.048s
sys 0m0.036s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.088s
user    0m0.048s
sys 0m0.040s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.088s
user    0m0.048s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac1.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.087s
user    0m0.064s
sys 0m0.028s
piousbox@piousbox-laptop:~/projects/trash$ time ruby fac2.rb
30414093201713378043612608166064768844377641568960512000000000000

real    0m0.089s
user    0m0.068s
sys 0m0.016s
piousbox@piousbox-laptop:~/projects/trash$ 

Làm thế nào để tôi mất thời gian trung bình để chạy tập lệnh? Tôi có thể phân tích và tính trung bình đầu ra của 100 timenhưng tôi tưởng tượng có một giải pháp tốt hơn?


Câu trả lời:


4

Không, ý tưởng trung bình của bạn là chính xác.

Việc thực thi tập lệnh phụ thuộc vào rất nhiều yếu tố và tuy nhiên, nó sẽ được phân chia giữa thời gian thiết lập (tải trình thông dịch trong bộ nhớ, thiết lập và có thể biên dịch mã thành mã byte hoặc mã máy) và thời gian thực hiện đúng.

Để tập trung tốt hơn vào thời gian thực hiện bên trong, bạn thực hiện vòng lặp trong chính tập lệnh (tức là thay vì tính một giai thừa, bạn tính toán 100 lần trong một lần thực thi tập lệnh. Tập lệnh sẽ được thiết lập một lần và thường trình bên trong sẽ thực thi 100 lần).

Để tập trung vào tổng thời gian, bạn thực thi tập lệnh một trăm lần và tính trung bình các kết quả. Tốt nhất, bạn nên tách riêng các thực thi đó đủ để hệ thống trả về trạng thái "tham chiếu" (hoặc trạng thái không liên quan đến tập lệnh) mỗi lần. Ví dụ, bản thân trình thông dịch sẽ được lưu trong bộ nhớ, do đó, lần thực thi đầu tiên của tập lệnh sẽ chậm hơn đáng kể so với các trình thông tin tiếp theo.

Để hiểu rõ hơn về thuật toán, tôi nghĩ cách tốt nhất là một cái gì đó như thế này (trên một máy nhàn rỗi khác):

  • bọc thuật toán trong một hàm duy nhất.
  • trong ứng dụng kiểm soát:
    • gọi hàm một lần
    • lấy thời gian của hệ thống ("đồng hồ treo tường") và thêm 10 (hoặc N hợp lý) giây
    • vào vòng lặp và bắt đầu đếm số lần lặp
    • sau mỗi cuộc gọi đến hàm, tăng bộ đếm
    • nếu thời gian hệ thống thấp hơn thời gian lưu, hãy thực hiện một vòng lặp khác
    • lấy chính xác N, có thể là dấu phẩy động, từ thời gian đồng hồ treo tường hiện tại
    • hiển thị bộ đếm chia cho N: đó là số lần lặp / giây.

Ứng dụng chỉ chạy một lần, tất cả các thiết lập và mồi được thực hiện bằng lần lặp đầu tiên chưa được xử lý, do đó, điều này sẽ giảm thiểu các chi phí (trừ khi có thể cho cuộc gọi thời gian).

Nếu hàm nhận được đầu vào, bạn sẽ cung cấp cho nó một chuỗi đầu vào ngẫu nhiên bằng cách sử dụng PRNG với giá trị cố định, để đảm bảo cả hai phiên bản của hàm được kiểm tra đều nhận được cùng một giá trị. Điều này tránh một chức năng hoạt động tốt hơn rõ ràng do "số may mắn" (ví dụ: tôi nhớ một biến thể của thuật toán Hillsort hoạt động tốt hơn nếu số lượng vật phẩm được sắp xếp ở dạng 2 k -1 với k k nhỏ ).


Phải, cảm ơn. Tôi nhận thấy rằng các cuộc gọi tiếp theo nơi nhận được ngắn hơn. Bây giờ tôi chạy vòng lặp bên trong các tập lệnh và thấy rằng một thuật toán chắc chắn nhanh hơn thuật toán kia.
Victor Piousbox

39

Bạn có thể chạy các lần lặp của chương trình trong một vòng lặp; và chia tổng thời gian cho số lần lặp:

time for i in {1..10}; do sleep 1; done
real    0m10.052s
user    0m0.005s
sys 0m0.018s

2
Siêu đơn giản, yêu nó. Tôi cũng chưa bao giờ thấy {1..10}trước đây và thấy bối rối rằng nó hoạt động, không thể tìm thấy nó trong hướng dẫn sử dụng bash. Điều đáng buồn là bạn không biết sự lây lan của kết quả của bạn (thời gian tối thiểu và tối đa).
w00t

@ w00t:man -P 'less +/Brace\ Expansion' bash
dùng2683246

Cảm ơn @ user2683246! Sau đó tôi cũng tìm thấy nó tại gnu.org/software/bash/manual/bash.html#Brace-Expansion - sử dụng ít btw. Bây giờ tôi cũng tò mò về việc khi nó xuất hiện trong bash
w00t

1
Aha, phiên bản 3, 10 năm sau khi tôi bắt đầu sử dụng bash :) tldp.org/LDP/abs/html/bashver3.html
w00t

2
Nếu điều này không hoạt động để đến nhân viên Google, có thể là do bạn không chạy bash. Hãy thử chạy /bin/bashtrước đây.
Cory Klein

14

có một công cụ được gọi là multitime thực hiện chính xác điều này: chạy lệnh nhiều lần, đo thời gian cần thiết (thời gian thực / người dùng / hệ thống với thời gian trung bình, tối thiểu / tối đa và trung bình được tính toán)

Chẳng hạn, để đo một tập lệnh tương tự 100 lần:

multitime -q -n 100 "fact1.sh"
===> multitime results
1: -q fact1.sh
            Mean        Std.Dev.    Min         Median      Max
real        0.122       0.032       0.086       0.116       0.171       
user        0.148       0.044       0.096       0.137       0.223       
sys         0.023       0.019       0.000       0.014       0.061 

12

Điều này đã cũ nhưng nó đã xuất hiện rất cao trên google khi tôi đang tìm kiếm một lệnh tôi đã sử dụng trước đây nhưng không thể tìm thấy. Dù sao, cách ưa thích của tôi để làm điều này là:

perf stat -r 10 -B sleep 1

Điều này cung cấp khá nhiều chi tiết bao gồm thời gian thực hiện trung bình ngay khi kết thúc:

1.002248382 seconds time elapsed                   ( +-  0.01% )


1

Hyperfine là một lựa chọn khác.

Sử dụng mẫu:

hyperfine --warmup 3 'ruby fac1.rb'

1
hyperfine tốt hơn nhiều so với các lựa chọn thay thế khác đến mức thật nực cười. Phát hiện các hoạt động cần thiết, khởi động, đầu ra đẹp, báo cáo đánh dấu, viết bằng rỉ sét, v.v.
Klas Mellbourn
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.