Nhận thời gian thực hiện chương trình trong trình bao


407

Tôi muốn thực thi một cái gì đó trong shell linux trong một vài điều kiện khác nhau và có thể xuất thời gian thực hiện của mỗi lần thực thi.

Tôi biết tôi có thể viết một kịch bản perl hoặc python sẽ làm điều này, nhưng có cách nào tôi có thể làm nó trong shell không? (xảy ra là bash)



Có thể có được Ticksnhư trường hợp cửa sổ?
miễn phí tousez

Câu trả lời:


534

Sử dụng timetừ khóa tích hợp:

$ thời gian giúp đỡ

thời gian: thời gian [-p] PIPELINE
    Thực thi PIPELINE và in tóm tắt về thời gian thực, thời gian CPU của người dùng,
    và thời gian CPU hệ thống dành cho việc thực thi PIPELINE khi nó kết thúc.
    Trạng thái trả về là trạng thái trả về của PIPELINE. Tùy chọn `-p '
    in tóm tắt thời gian trong một định dạng hơi khác nhau. Cái này dùng
    giá trị của biến TIMEFORMAT là định dạng đầu ra.

Thí dụ:

$ time sleep 2
0m2.009s thật
người dùng 0m0.000s
sys 0m0.004s

1
Làm thế nào điều này được sử dụng trên một lệnh như thế time -p i=x; while read line; do x=x; done < /path/to/file.txtnào? Nó lập tức trả về 0,00 trừ khi tôi không đặt bất cứ thứ gì trước vòng lặp while .. cái gì cho?
natli

đây là phiên bản 'thời gian' nghèo nàn, bash dựng sẵn. lệnh 'thời gian' bên ngoài ở đâu?
Znik

6
@Znik, thử / usr / bin / lần
Mark Rajcok

10
@natli: Mặc dù timecó thể đặt thời gian cho toàn bộ đường ống (theo nguyên tắc là một từ khóa Bash ), bạn cần sử dụng lệnh nhóm ( { ...; ...; }) để tính thời gian cho nhiều lệnh:time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
mkuity0

2
Để xem tất cả các phiên bản thời gian bạn đã cài đặt trên hệ thống của mình, bạn có thể sử dụngtype -a time
spinup

120

Bạn có thể nhận được thông tin chi tiết hơn nhiều so với bash tích hợp time(mà Robert Gamble đề cập) sử dụng thời gian (1) . Thông thường đây là /usr/bin/time.

Lưu ý của biên tập viên: Để đảm bảo rằng bạn đang gọi tiện ích bên ngoài time thay vì time từ khóa của shell , hãy gọi nó như /usr/bin/time.
timelà một tiện ích bắt buộc POSIX , nhưng tùy chọn duy nhất cần có để hỗ trợ là -p.
Các nền tảng cụ thể triển khai các tiện ích mở rộng không chuẩn, cụ thể: -vhoạt động với tiện ích của GNUtime , như được trình bày bên dưới (câu hỏi được gắn thẻ); việc triển khai BSD / macOS sử dụng -lđể tạo đầu ra tương tự - xem man 1 time.

Ví dụ về đầu ra dài dòng:


$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0


2
bạn sẽ không biết gói debian nào sẽ đến từ đâu? dường như không được cài đặt theo mặc định
ʞɔIu

1
Tôi đã tham khảo bài viết của bạn Robert. Trừ khi bạn có nghĩa là lệnh bạn đề xuất không phải là bash tích hợp?
grepsedawk

24
Thật đáng ngạc nhiên, nó được cài đặt từ một gói gọi là "thời gian".
Paul Tomblin

2
Kết quả từ vẻ / usr / bin / thời gian như "0.00user 0.00system 0: 02.00elapsed 0% CPU (0avgtext + 0avgdata 0maxresident) k 0inputs + 0outputs (0major + 172minor) pagefaults 0swaps"
Paul Tomblin

4
@Nick: "sudo apt-get time time".
Robert Gamble

79
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"

14
Có cách đơn giản hơn nhiều. Bash tính toán biến tự động đặc biệt $ SECONDS, sau đó tính toán lại dựa trên lệnh ngày bên ngoài là không cần thiết. Biến $ SECONDS giữ cho tập lệnh bash chạy bao nhiêu giây khi nó bắt đầu. Biến này có một số tài sản đặc biệt. Xem trang người đàn ông: D
Znik

Tôi đã thử cả hai cách trên & phương pháp trong bình luận. Trong lần đầu tiên tôi nhận được một lỗi 'biến bất hợp pháp' và lần thứ 2 tôi nhận được 'biến không xác định'
DrBwts

45

Để đo delta theo từng dòng, hãy thử gnomon .

Một tiện ích dòng lệnh, giống như ts của moreutils, để thêm thông tin dấu thời gian vào đầu ra tiêu chuẩn của một lệnh khác. Hữu ích cho các quy trình dài mà bạn muốn ghi lại lịch sử về những gì mất quá nhiều thời gian.

Bạn cũng có thể sử dụng các tùy chọn --highvà / hoặc --mediumđể chỉ định ngưỡng độ dài tính bằng giây, qua đó gnomon sẽ làm nổi bật dấu thời gian bằng màu đỏ hoặc màu vàng. Và bạn có thể làm một vài điều khác nữa.

thí dụ


3
Mẹo hay, nhưng chỉ cần rõ ràng: điều này hữu ích cho việc định thời theo từng dòng , nhưng chi phí chung của việc lấy thời gian chi tiết nhỏ như vậy làm tăng đáng kể thời gian tổng thể .
mkuity0

2
Tiện ích tuyệt vời .. Cảm ơn bạn đã chia sẻ
Kishan B

19

Nếu bạn muốn độ chính xác cao hơn, hãy sử dụng %Nvới date(và sử dụng bccho diff, vì $(())chỉ xử lý các số nguyên).

Đây là cách thực hiện:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

Thí dụ:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

Kết quả:

Execution time: 0.104623 seconds

15

Nếu bạn định sử dụng thời gian sau để tính toán, hãy tìm hiểu cách sử dụng -ftùy chọn /usr/bin/timeđể xuất tiết kiệm thời gian. Đây là một số mã tôi đã sử dụng gần đây để nhận và sắp xếp thời gian thực hiện của toàn bộ các chương trình của sinh viên:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

Sau đó tôi đã nối tất cả các $timefiletệp và chuyển đầu ra thành một trình thông dịch Lua . Bạn có thể làm tương tự với Python hoặc bash hoặc bất kỳ cú pháp yêu thích nào của bạn. Tôi yêu kỹ thuật này.


Lưu ý: Đường dẫn đầy đủ /usr/bin/timelà cần thiết bởi vì mặc dù which timesẽ cho bạn biết khác, nếu bạn chỉ chạy time, nó sẽ chạy phiên bản shell của timebạn không chấp nhận bất kỳ đối số nào.
Kevin Dice

Tôi sẽ đi với env time:-)
Ciro Santilli 冠状 病 六四 事件

13

Nếu bạn chỉ cần độ chính xác đến giây, bạn có thể sử dụng $SECONDSbiến dựng sẵn , đếm số giây mà vỏ đã chạy.

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done

10

Bạn có thể sử dụng timesubshell () :

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

Hoặc trong cùng một vỏ {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}

Bạn đã đăng hai đoạn mã giống hệt nhau. Bạn phải có ý nghĩa để có một cái gì đó khác nhau ở đó.
stason

3
@StasBekman là không đúng sự thật, lần đầu tiên sử dụng (& )(bối cảnh mới, subshell ) và khác với {& }(cùng vỏ, cùng bối cảnh)
Eduardo Cuomo

Aha! Tôi đã nhìn hai người rất chăm chỉ và không thấy sự khác biệt. Cảm ơn bạn đã làm rõ rằng {} vs ().
stason

2

Cách là

$ > g++ -lpthread perform.c -o per
$ > time ./per

đầu ra là >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s

Không cần sử dụng -lphtreadhoặc -othẻ. Chỉ cần sử dụng timelệnh, mà câu trả lời được chấp nhận giải thích tốt hơn.
Dennis

7
Đó là một ví dụ. Đó là màn trình diễn của tôi có luồng nên tôi cần -lpthread và để nhận dạng đơn giản, nó là -o per.
Robel Sharma

0

một phương pháp có thể đơn giản (có thể không đáp ứng các nhu cầu khác nhau của người dùng) là sử dụng shell PROMPT.it là một giải pháp đơn giản có thể hữu ích trong một số trường hợp. Bạn có thể sử dụng tính năng nhắc bash như trong ví dụ dưới đây:

xuất PS1 = '[\ t \ u @ \ h] \ $' 

Lệnh trên sẽ dẫn đến việc thay đổi dấu nhắc shell thành:

[HH: MM: Tên người dùng SS @ tên máy chủ] $ 

Mỗi khi bạn chạy một lệnh (hoặc nhấn enter) trở lại dấu nhắc shell, dấu nhắc sẽ hiển thị thời gian hiện tại.

lưu ý:
1) lưu ý rằng nếu bạn đợi một thời gian trước khi bạn nhập lệnh tiếp theo, thì lần này cần phải xem xét, tức là thời gian hiển thị trong dấu nhắc shell là dấu thời gian khi dấu nhắc shell được hiển thị, không phải khi bạn nhập lệnh. một số người dùng chọn nhấn phím Enter để nhận lời nhắc mới với dấu thời gian mới trước khi họ sẵn sàng cho lệnh tiếp theo.
2) Có các tùy chọn và sửa đổi có sẵn khác có thể được sử dụng để thay đổi dấu nhắc bash, tham khảo (man bash) để biết thêm chi tiết.


Không phải là điểm khi chương trình thực thi, mà là thời gian thực hiện chương trình.
Gen Chen Chen
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.