Phổ biến không bash `thời gian chuẩn thay thế? [đóng cửa]


10

Để so sánh thời gian chạy các script giữa vỏ khác nhau, một số câu trả lời SE đề nghị sử dụng bash's built-in time lệnh, như vậy:

time bash -c 'foo.sh'
time dash -c 'foo.sh'

... vv , cho mọi vỏ để kiểm tra. Các điểm chuẩn như vậy không thể loại bỏ thời gian để mỗi vỏ tải và tự khởi tạo . Ví dụ: giả sử cả hai lệnh trên được lưu trữ trên một thiết bị chậm với tốc độ đọc của đĩa mềm ban đầu , (124KB / s), dash( thực thi ~ 150K ) sẽ tải nhanh hơn khoảng 7 lần so với bash( ~ 1M ), vỏ thời gian tải sẽ làm lệch các timecon số - thời gian tải trước của các vỏ đó không liên quan đến việc đo thời gian chạy của foo.shmỗi vỏ sau khi đạn được nạp.

Cái nào tốt nhất cho di động và sử dụng chung để chạy cho thời gian tập lệnh có thể chạy từ bên trong mỗi shell? Vì vậy, đoạn mã trên sẽ trông giống như:

bash -c 'general_timer_util foo.sh'
dash -c 'general_timer_util foo.sh'

NB: không có vỏ built-in time lệnh, vì không ai là xách tay hoặc nói chung.


Tốt hơn nữa nếu việc sử dụng cũng có thể định chuẩn thời gian được thực hiện bởi các lệnh và đường ống nội bộ của shell, mà không cần người dùng trước tiên phải bọc chúng trong một tập lệnh. Cú pháp nhân tạo như thế này sẽ giúp:

general_timer_util "while read x ; do echo x ; done < foo"

Một số vỏ ' timecó thể quản lý này. Ví dụ bash -c "time while false ; do : ; done"công trình. Để xem những gì hoạt động, (và không), trên hệ thống của bạn hãy thử:

tail +2 /etc/shells | 
while read s ; do 
    echo $s ; $s -c "time while false ; do : ; done" ; echo ----
done

6
Chỉ cần sử dụng /usr/bin/time?
Kusalananda

1
Tôi không hiểu làm thế nào bất kỳ người không xây dựng nào có thể vừa "loại bỏ thời gian cho mỗi trình bao tải và tự khởi tạo" và thực thi một tập lệnh độc lập trong khi là "di động và chung".
Michael Homer

1
Đó không phải là một câu trả lời cho câu hỏi, nó là một gợi ý cho bạn để làm rõ những gì bạn muốn.
Michael Homer

1
Tôi đã đăng nỗ lực tốt nhất của mình, nhưng tôi nghĩ rằng câu hỏi vẫn chưa được xác định rõ về chính xác những gì nó thực sự cố gắng đạt được.
Michael Homer

2
Bạn có ý nghĩa gì bởi những người di động hay nói chung là gì? Các nội dung shell là di động (hoạt động trên nhiều hệ thống) và tổng quát hơn (hoạt động trong nhiều trường hợp hơn, vì chúng có thể có thời gian khác với việc thực thi tệp) như lệnh bên ngoài. Vấn đề gì bạn đang cố gắng giải quyết?
Gilles 'SO- ngừng trở nên xấu xa'

Câu trả lời:


10

Bạn nên lưu ý rằng timeđược chỉ định bởi POSIX và AFAICT tùy chọn duy nhất mà POSIX đề cập ( -p) được hỗ trợ chính xác bởi các trình bao khác nhau:

$ bash -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ dash -c 'time -p echo'

real 0.01
user 0.00
sys 0.00
$ busybox sh -c 'time -p echo'

real 0.00
user 0.00
sys 0.00
$ ksh -c 'time -p echo'       

real 0.00
user 0.00
sys 0.00

1
Vấn đề là để có thể so sánh thời gian, kết quả phải được tính theo cùng thời gian thực hiện time. Nó có thể so sánh với việc cho phép những người chạy nước rút đo thời gian của chính họ trên 100m, thay vì làm điều đó với một đồng hồ cùng một lúc. Đây rõ ràng là trò đùa, nhưng vẫn ...
Kusalananda

@Kusalananda Tôi nghĩ vấn đề là OP nghĩ timekhông thể mang theo được; nó dường như là di động. (Tuy nhiên, tôi đồng ý với quan điểm của bạn về khả năng so sánh)
muru

@muru, trên hệ thống của tôi dash -c 'time -p while false ; do : ; done'trả về "thời gian: không thể chạy trong khi: Không có tệp hoặc thư mục nào như vậy <cr> Lệnh đã thoát với lỗi không trạng thái 127" .
agc

1
@agc POSIX cũng cho biết: "Thuật ngữ tiện ích được sử dụng, thay vì lệnh, để làm nổi bật thực tế là các lệnh ghép vỏ, đường ống, tích hợp đặc biệt, v.v., không thể được sử dụng trực tiếp. Tuy nhiên, tiện ích bao gồm các chương trình ứng dụng người dùng và shell script, không chỉ là các tiện ích tiêu chuẩn. " (xem phần RATIONALE)
muru


7

Tôi sử dụng lệnh GNU date , hỗ trợ bộ định thời độ phân giải cao:

START=$(date +%s.%N)
# do something #######################

"$@" &> /dev/null

#######################################
END=$(date +%s.%N)
DIFF=$( echo "scale=3; (${END} - ${START})*1000/1" | bc )
echo "${DIFF}"

Và sau đó tôi gọi kịch bản như thế này:

/usr/local/bin/timing dig +short unix.stackexchange.com
141.835

Đơn vị đầu ra tính bằng mili giây.


1
Giả sử thời gian (thời gian kỷ nguyên) không thay đổi ở giữa. Không thể nghĩ ra một trường hợp trong thực tế, nơi nó sẽ gây ra vấn đề nhưng vẫn đáng được đề cập.
phk

1
Bạn nên thêm rằng điều này đòi hỏi GNU date.
Kusalananda

@phk hãy giải thích?
Rabin

1
@Rabin Hãy nói rằng khách hàng NTP của bạn gặp sự cố và cập nhật và thay đổi đồng hồ của bạn giữa nơi STARTENDđược đặt, thì điều này rõ ràng sẽ ảnh hưởng đến kết quả của bạn. Không biết bạn cần nó chính xác đến mức nào và liệu nó có quan trọng trong trường hợp của bạn hay không nhưng như tôi đã nói, một điều cần lưu ý. (Câu chuyện thú vị: Tôi biết một phần mềm mà chính xác nó đã dẫn đến một kết quả bất ngờ tiêu cực - nó được sử dụng để tính toán thông - mà sau đó đã phá vỡ một vài điều.)
PHK

1
Ngoài ra, không một số khách hàng NTP làm chậm và tăng tốc đồng hồ, thay vì thực hiện "nhảy" trong thời gian hệ thống? Nếu bạn có một ứng dụng khách NTP như thế và bạn đã thực hiện một số thời gian vào tối ngày hôm qua, họ có thể bị khách hàng NTP sai lệch "dự đoán" bước nhảy vọt thứ hai. (Hoặc đồng hồ hệ thống chỉ đơn giản chạy đến 61 trong trường hợp đó?)
Jörg W Mittag

6

Các timetiện ích thường được xây dựng vào vỏ, như bạn đã thấy, mà làm cho nó vô dụng như một bộ đếm thời gian "trung lập".

Tuy nhiên, tiện ích thường có sẵn như một tiện ích bên ngoài /usr/bin/time, có thể được sử dụng để thực hiện các thử nghiệm thời gian mà bạn đề xuất.

$ bash -c '/usr/bin/time foo.sh'

Làm thế nào để "loại bỏ thời gian cho mỗi vỏ để tải và tự khởi tạo"?
Michael Homer

1
Nếu foo.shcó thể thực thi được và có shebang, thì cái này luôn chạy nó với cùng một shell nó tính thời gian khởi động của shell đó, vì vậy đây không phải là điều OP muốn. Nếu foo.shthiếu một trong số đó, thì điều này hoàn toàn không hoạt động.
Kevin

@Kevin Rất đúng. Tôi chỉ timexem xét "không có vỏ tích hợp ". Thời gian khởi động vỏ có thể phải được đo riêng.
Kusalananda

1
Tôi không biết bất kỳ shell nào có timelệnh dựng sẵn. Tuy nhiên, nhiều shell bao gồm bashmột timetừ khóa có thể được sử dụng cho các đường ống thời gian. Để vô hiệu hóa từ khóa đó để timelệnh (trong hệ thống tệp) được sử dụng, bạn có thể trích dẫn nó như thế nào "time" foo.sh. Xem thêm unix.stackexchange.com/search?q=user%3A22565+time+keyword
Stéphane Chazelas

6

Đây là một giải pháp:

  1. loại bỏ [s] thời gian cần thiết cho mỗi shell để tải và tự khởi tạo

  2. có thể được chạy từ bên trong mỗi vỏ

  3. Công dụng

    không có timelệnh tích hợp shell nào , vì không có lệnh nào là di động hay chung

  4. Hoạt động trong tất cả các vỏ tương thích POSIX.
  5. Hoạt động trên tất cả các hệ thống tương thích POSIX và XSI tương thích với trình biên dịch C hoặc nơi bạn có thể biên dịch trước một tệp thực thi C.
  6. Sử dụng cùng thời gian thực hiện trên tất cả các shell.

Có hai phần: một chương trình C ngắn kết thúc gettimeofday, không dùng nữa nhưng vẫn dễ mang theo hơn clock_gettimevà một tập lệnh shell ngắn sử dụng chương trình đó để có được đồng hồ có độ chính xác micro giây đọc cả hai mặt của nguồn kịch bản. Chương trình C là cách duy nhất di động và tối thiểu để có được độ chính xác dưới giây trên dấu thời gian.

Đây là chương trình C epoch.c:

#include <sys/time.h>
#include <stdio.h>
int main(int argc, char **argv) {
    struct timeval time;
    gettimeofday(&time, NULL);
    printf("%li.%06i", time.tv_sec, time.tv_usec);
}

Và kịch bản shell timer:

#!/bin/echo Run this in the shell you want to test

START=$(./epoch)
. "$1"
END=$(./epoch)
echo "$END - $START" | bc

Đây là tiêu chuẩn ngôn ngữ lệnh shellbcvà nên hoạt động như một kịch bản dưới bất kỳ vỏ POSIX tương thích.

Bạn có thể sử dụng như:

$ bash timer ./test.sh
.002052
$ dash timer ./test.sh
.000895
$ zsh timer ./test.sh
.000662

Nó không đo thời gian của hệ thống hoặc người dùng, chỉ có thời gian trôi qua đồng hồ treo tường không đơn điệu. Nếu đồng hồ hệ thống thay đổi trong quá trình thực thi tập lệnh, điều này sẽ cho kết quả không chính xác. Nếu hệ thống đang tải, kết quả sẽ không đáng tin cậy. Tôi không nghĩ rằng bất cứ điều gì tốt hơn có thể được di chuyển giữa các vỏ.

Một giờ kịch bản biến đổi có thể sử dụng evalthay vì để chạy các lệnh bên ngoài của một kịch bản.


Thật trùng hợp, ngay trước khi đọc bài viết này, (và dòng cuối cùng về eval), tôi đã tinh chỉnh kịch bản trong Rabin câu trả lời 's để bao gồm eval "$@", vì vậy nó có thể chạy shell lệnh nội trú khi đang bay.
agc

4

Nhiều lần sửa đổi giải pháp bằng cách sử dụng /proc/uptimedc/ bc/ awktrong các phần lớn nhờ đầu vào của agc :

#!/bin/sh

read -r before _ < /proc/uptime

sleep 2s # do something...

read -r after _ < /proc/uptime

duration=$(dc -e "${after} ${before} - n")
# Alternative using bc:
#   duration=$(echo "${after} - ${before}" | bc)
# Alternative using awk:
#   duration=$(echo "${after} ${before}" | awk '{print $1 - $2}')

echo "It took $duration seconds."

Giả định rõ ràng là /proc/uptimetồn tại và có một hình thức nhất định.


3
Điều này sẽ làm cho nó di động giữa các shell, nhưng không thể di chuyển giữa các triển khai Unix vì một số đơn giản là thiếu /prochệ thống tập tin. Nếu điều này có liên quan hay không, tôi không biết.
Kusalananda

1
Để nhấn mạnh, Q này gợi ý tốc độ đĩa mềm hoặc tệ hơn. Trong trường hợp đó, chi phí tải awkcó thể là đáng kể. Có thể b=$(cat /proc/uptime)trước, rồi a=$(cat /proc/uptime)sau, sau đó phân tích $ a$ b và trừ đi.
agc

@agc Đầu vào tốt, cảm ơn, tôi đã thêm một số giải pháp thay thế cho phù hợp.
phk

1
Không nghĩ về nó trước đó, nhưng nếu builtins thích readtốt hơn cat, đây sẽ là sạch hơn (và một chút nhanh hơn): read before dummyvar < /proc/uptime ;sleep 2s;read after dummyvar < /proc/uptime; duration=$(dc -e "${after} ${before} - n");echo "It took $duration seconds."
AGC
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.