วิธีรับเวลาประมวลผลของสคริปต์อย่างมีประสิทธิภาพ


340

ฉันต้องการที่จะแสดงเวลาที่เสร็จสมบูรณ์ของสคริปต์

สิ่งที่ฉันทำในปัจจุบันคือ -

#!/bin/bash
date  ## echo the date at start
# the script contents
date  ## echo the date at end

นี่เป็นเพียงการแสดงเวลาเริ่มต้นและสิ้นสุดของสคริปต์ เป็นไปได้ไหมที่จะแสดงเอาต์พุตแบบละเอียดเช่นเวลาตัวประมวลผล / เวลา io เป็นต้น



ฉันคิดว่าคำตอบที่ยอมรับในปัจจุบันนั้นไม่เพียงพอเพราะความผันผวนทางโลก
LéoLéopold Hertz 준영

1
@CiroSantilli 烏坎事件 2016 六四事件法轮功ฉันคิดว่ากระทู้ที่คุณเสนอยังไม่เพียงพอที่จะกำจัดผลกระทบของเหตุการณ์ทางโลก
LéoLéopold Hertz 준영

ที่เกี่ยวข้องเพิ่มเติม: stackoverflow.com/questions/5152858/ …หรือค่อนข้างunix.stackexchange.com/questions/334145/…
phk

มีคำสั่งที่คุณสามารถเรียกใช้แล้วมันจะคำสั่ง unix ทั้งหมดโดยอัตโนมัติลืมวิธีการเปิดใช้งาน?
powder366

คำตอบ:


449

เพียงใช้timeเมื่อคุณเรียกสคริปต์:

time yourscript.sh

61
เอาท์พุทนี้สามครั้ง: real, และuser sysสำหรับความหมายของเหล่านี้ให้ดูที่นี่
Garrett

27
และ "ของจริง" อาจเป็นสิ่งที่ผู้คนต้องการทราบ - "ของจริงคือเวลาของนาฬิกาแขวน - เวลาตั้งแต่ต้นจนจบการโทร"
Brad Parks

3
มีวิธีการจับ stdout เป็นไฟล์หรือไม่? ตัวอย่างเช่นบางสิ่งบางอย่างtime $( ... ) >> out.txt
Jon

1
นอกจากนี้คุณยังสามารถทำตามลำดับของคำสั่งในบรรทัดคำสั่งเช่น:time (command1 && command2)
ตอบสนอง

1
หรือเขาสามารถทำได้ในสคริปต์ของเขาเพียงทำ: echo $ SECONDS สมมติว่ามันทุบตี ....
Crossfit_and_Beer

170

ถ้าtimeไม่ใช่ตัวเลือก

start=`date +%s`
stuff
end=`date +%s`

runtime=$((end-start))

30
โปรดทราบว่าวิธีนี้ใช้ได้เฉพาะในกรณีที่คุณไม่ต้องการความแม่นยำระดับรอง สำหรับการใช้งานบางอย่างที่อาจเป็นที่ยอมรับสำหรับผู้อื่นที่ไม่ใช่ เพื่อความแม่นยำที่ดีกว่าเล็กน้อย (คุณยังคงอัญเชิญdateครั้งที่สองเช่นเพื่อให้คุณที่อาจจะดีที่สุดจะได้รับความแม่นยำมิลลิวินาทีในการปฏิบัติและอาจจะน้อยกว่า) date +%s.%Nลองใช้ ( %Nเป็นนาโนวินาทีตั้งแต่วินาทีที่ทั้งคู่)
CVn

จุดดี. ฉันคิดว่าหลังจากออกจากแป้นพิมพ์ แต่ไม่ได้กลับมา ^^ โปรดจำไว้ด้วย OP ว่า "วันที่" จะเพิ่มมิลลิวินาทีในเวลาทำงาน
Rob Bos

2
@ChrisH โอ้ ดีชี้มันออกมา; bash การขยายเลขคณิตเป็นจำนวนเต็มเท่านั้น ฉันเห็นสองตัวเลือกที่ชัดเจน ทิ้งช่วงเวลาในสตริงรูปแบบวันที่ (และปฏิบัติต่อค่าผลลัพธ์เป็นนาโนวินาทีตั้งแต่ยุค) ดังนั้นใช้date +%s%Nหรือใช้สิ่งที่มีความสามารถมากขึ้นเช่นbcการคำนวณรันไทม์ที่เกิดขึ้นจริงจากค่าทั้งสองเช่น jwchew แนะนำ ถึงกระนั้นฉันรู้สึกว่าวิธีนี้เป็นวิธีที่ไม่ดีอย่างยิ่งในการทำเช่นนั้น timeจะดีกว่ามากถ้ามีด้วยเหตุผลที่กล่าวไว้ข้างต้น
CVN

10
เพียงติดตั้งbcแล้วทำเช่นนี้:runtime=$( echo "$end - $start" | bc -l )
redolent

10
หากสคริปต์ของคุณใช้เวลาหลายนาทีให้ใช้:echo "Duration: $((($(date +%s)-$start)/60)) minutes
rubo77

75

เพียงแค่โทรtimesโดยไม่มีข้อโต้แย้งเมื่อออกจากสคริปต์ของคุณ

ด้วยkshหรือzshคุณสามารถใช้timeแทน ด้วยzsh, timeยังจะให้เวลาของนาฬิกาผนังนอกเหนือไปจากผู้ใช้และระบบเวลา CPU

เพื่อรักษาสถานะการออกจากสคริปต์ของคุณคุณสามารถทำได้:

ret=$?; times; exit "$ret"

หรือคุณสามารถเพิ่มกับดักในEXIT:

trap times EXIT

ด้วยวิธีนี้เวลาจะถูกเรียกเมื่อใดก็ตามที่เชลล์ออกและสถานะการออกจะถูกเก็บรักษาไว้

$ bash -c 'trap times EXIT; : {1..1000000}'
0m0.932s 0m0.028s
0m0.000s 0m0.000s
$ zsh -c 'trap time EXIT; : {1..1000000}'
shell  0.67s user 0.01s system 100% cpu 0.677 total
children  0.00s user 0.00s system 0% cpu 0.677 total

นอกจากนี้ยังทราบว่าทั้งหมดของbash, kshและzshมี$SECONDSตัวแปรพิเศษที่โดยอัตโนมัติได้รับเพิ่มขึ้นทุกวินาที ทั้งในzshและksh93ตัวแปรนั้นยังสามารถสร้างจุดลอยตัว (พร้อมtypeset -F SECONDS) เพื่อความแม่นยำมากขึ้น นี่เป็นเพียงนาฬิกาเวลาเท่านั้นไม่ใช่เวลา CPU


12
ตัวแปร $ SECONDS นั้นมีประโยชน์มากขอบคุณ!
andybuckley

วิธีการของคุณกำจัดผลกระทบของเหตุการณ์ทางโลกหรือไม่? - - ฉันคิดว่าแนวทางของคุณใกล้timeเข้ามาแล้วก่อนหน้านี้ - - ฉันคิดว่าtimeitวิธีที่นำเสนอในรหัส MATLAB มีประโยชน์ที่นี่
LéoLéopold Hertz 준영

2
สวัสดี @ Stéphane Chazelas ฉันพบว่าtimesไม่ให้เวลากำแพงใช่มั้ย ตัวอย่างเช่นbash -c 'trap times EXIT;sleep 2'
user15964

แอพที่คล้ายกับunix.stackexchange.com/questions/269789/…
akhan

32

ฉันช้าไปเล็กน้อยกับ bandwagon แต่ต้องการโพสต์คำตอบของฉัน (สำหรับความแม่นยำย่อยที่สอง) ในกรณีที่คนอื่น ๆ สะดุดกับหัวข้อนี้ผ่านการค้นหา เอาต์พุตอยู่ในรูปแบบของวันชั่วโมงนาทีและวินาทีสุดท้าย:

res1=$(date +%s.%N)

# do stuff in here

res2=$(date +%s.%N)
dt=$(echo "$res2 - $res1" | bc)
dd=$(echo "$dt/86400" | bc)
dt2=$(echo "$dt-86400*$dd" | bc)
dh=$(echo "$dt2/3600" | bc)
dt3=$(echo "$dt2-3600*$dh" | bc)
dm=$(echo "$dt3/60" | bc)
ds=$(echo "$dt3-60*$dm" | bc)

printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds

หวังว่าคนที่อยู่ข้างนอกพบว่าสิ่งนี้มีประโยชน์!


1
ฉันเดาว่าไม่มีวิธีอื่น (ทุบตีเท่านั้น) ยกเว้นการใช้ 'bc' เพื่อทำการคำนวณ BTW สคริปต์ที่ดีจริง ๆ ;)
tvl

1
ระวังว่า FreeBSD dateนั้นไม่รองรับความแม่นยำย่อยวินาทีและจะต่อท้าย“” ตามตัวอักษรNไปยังเวลาประทับ
Anton Samsonov

1
สคริปต์ที่ดีมาก แต่ทุบตีของฉันไม่ได้จัดการกับส่วนย่อยที่สอง ฉันยังได้เรียนรู้ว่า / 1 ใน bc ได้แยกออกจากกันได้อย่างมีประสิทธิภาพดังนั้นฉันจึงเพิ่ม @ / 1 @ ลงในการคำนวณ $ ds และแสดงสิ่งที่ดีมากตอนนี้!
Daniel

1
BC สนับสนุน dt2=$(echo "$dt%86400" | bc)modulo: แค่พูดว่า ... BTW ฉันชอบแบบฟอร์มนี้dt2=$(bc <<< "${dt}%86400")แต่มันเป็นเรื่องส่วนตัว
Dani_l

16

วิธีการของฉันสำหรับbash:

# Reset BASH time counter
SECONDS=0
    # 
    # do stuff
    # 
ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"

นี่จะแสดงเวลาที่ผ่านไป แต่จะไม่แสดง "เอาท์พุทเม็ดเล็กละเอียดเช่นเวลาประมวลผลเวลา I / O" ตามที่ร้องขอในคำถาม
roaima

3
ผู้ที่ค้นหาคำตอบของคำถามที่ถูกวางมีแนวโน้มที่จะพบว่าวิธีนี้มีประโยชน์ ความคิดเห็นของคุณน่าจะตอบคำถาม OPs ได้ดียิ่งขึ้น
ทำเครื่องหมาย

5
#!/bin/bash
start=$(date +%s.%N)

# HERE BE CODE

end=$(date +%s.%N)    
runtime=$(python -c "print(${end} - ${start})")

echo "Runtime was $runtime"

ใช่สิ่งนี้เรียกว่า Python แต่ถ้าคุณสามารถอยู่กับมันได้นี่เป็นคำตอบที่ค่อนข้างดี


5
ระวังว่าการรันpythonคำสั่งนั้นในเชลล์ย่อยและการอ่านเอาต์พุตจะใช้เวลานานหลายล้านนาโนวินาทีในระบบปัจจุบันส่วนใหญ่ dateเดียวกันสำหรับการทำงาน
Stéphane Chazelas

7
"nanoseconds หลายล้าน" คือหลายมิลลิวินาที โดยทั่วไปแล้วคนทุบตีเวลาทุบตีจะไม่กังวลกับสิ่งนั้นมากนัก (เว้นแต่พวกเขาจะเรียกใช้สคริปต์หลายพันล้านรายการต่อเมกะไบต์วินาที)
Zilk

2
โปรดสังเกตด้วยว่าแม้ว่าการคำนวณจะกระทำภายในกระบวนการไพ ธ อนก็ตาม แต่ค่าเหล่านั้นจะถูกรวบรวมทั้งหมดก่อนที่จะเรียกใช้งานไพ ธ อน เวลาดำเนินการของสคริปต์จะถูกวัดอย่างถูกต้องโดยไม่มีค่าใช้จ่าย "ล้าน nanoseconds"
Victor Schröder

5

คำถามนี้ค่อนข้างเก่า แต่ในการพยายามหาวิธีที่ฉันโปรดปรานในการทำกระทู้นี้ขึ้นมาสูง ... และฉันประหลาดใจที่ไม่มีใครพูดถึงมัน:

perf stat -r 10 -B sleep 1

'perf' เป็นเครื่องมือวิเคราะห์ประสิทธิภาพที่รวมอยู่ในเคอร์เนลภายใต้ 'tools / perf' และมักจะติดตั้งเป็นแพ็คเกจแยกต่างหาก ('perf' ใน CentOS และ 'linux-tools' บน Debian / Ubuntu) Linux Kernal perf Wikiมีข้อมูลเพิ่มเติมมากมาย

การรัน 'perf stat' ให้รายละเอียดเล็กน้อยรวมถึงเวลาดำเนินการเฉลี่ยในตอนท้าย:

1.002248382 seconds time elapsed                   ( +-  0.01% )

2
คือperfอะไร
B Layer

@B Layer - แก้ไขคำตอบของฉันเพื่อให้คำอธิบายสั้น ๆ ของ 'perf'
Zaahid

1
perf statตอนนี้บ่นเกี่ยวกับ "คุณอาจไม่ได้รับอนุญาตให้รวบรวมสถิติ" นอกจากว่าคุณจะรันคำสั่งด้วยsudoซึ่งทำให้มันไร้ประโยชน์ในทุกสถานการณ์ที่คุณไม่ได้เป็นเจ้าของเครื่องเป้าหมายอย่างสมบูรณ์
alamar

4

ฟังก์ชันเชลล์ขนาดเล็กที่สามารถเพิ่มก่อนคำสั่งเพื่อวัดเวลา:

tm() {
  s=$(date +%s)
  $@
  rc=$?
  echo "took $[$(date +%s)-$s] seconds. return code $rc" >&2
  return $rc
}

จากนั้นใช้ในสคริปต์ของคุณหรือบนบรรทัดคำสั่งของคุณเช่น:

tm the_original_command with all its parameters

มันจะคุ้มค่าที่จะเพิ่มมิลลิวินาทีลอง ilke s=$(date +%s000)ไม่แน่ใจว่ามันทำงาน
loretoparisi

3

นี่คือรูปแบบของคำตอบของ Alex ฉันสนใจแค่นาทีและวินาทีเท่านั้น แต่ฉันก็ต้องการให้ฟอร์แมตนั้นแตกต่างกัน ดังนั้นฉันจึงทำสิ่งนี้:

start=$(date +%s)
end=$(date +%s)
runtime=$(python -c "print '%u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)")

1
ทำไมต้องลงคะแนน ฉันมีข้อบกพร่องหรือไม่?
mpontillo

3
#!/bin/csh
#PBS -q glean
#PBS -l nodes=1:ppn=1
#PBS -l walltime=10:00:00
#PBS -o a.log
#PBS -e a.err
#PBS -V
#PBS -M shihcheng.guo@gmail.com
#PBS -m abe
#PBS -A k4zhang-group
START=$(date +%s)
for i in {1..1000000}
do
echo 1
done
END=$(date +%s)
DIFF=$(echo "$END - $START" | bc)
echo "It takes DIFF=$DIFF seconds to complete this task..."

7
สิ่งนี้แตกต่างจากคำตอบอื่น ๆ ที่ให้ไว้แล้วซึ่งใช้dateก่อนและหลังสคริปต์และส่งออกความแตกต่างระหว่างพวกเขาอย่างไร
Eric Renouf

2

การใช้bash เท่านั้นยังสามารถวัดและคำนวณระยะเวลาสำหรับส่วนของเชลล์สคริปต์ (หรือเวลาที่ผ่านไปสำหรับสคริปต์ทั้งหมด):

start=$SECONDS

... # do time consuming stuff

end=$SECONDS

ตอนนี้คุณสามารถพิมพ์ความแตกต่าง:

echo "duration: $((end-start)) seconds."

หากคุณต้องการระยะเวลาที่เพิ่มขึ้นให้ทำ:

echo "duration: $((SECONDS-start)) seconds elapsed.."

คุณยังสามารถเก็บระยะเวลาในตัวแปร:

let diff=end-start

^ นี่คือคำตอบของคน หรือมากกว่านั้นง่ายๆเพียง: $ SECONDS ในตอนท้าย มันเป็นตัวแปร Bash ของ BUILT-IN คำตอบอื่น ๆ ทั้งหมดเป็นเพียงการทำงานพิเศษเพื่อคิดค้นล้อนี้อีกครั้ง ...
Crossfit_and_Beer

2

โดยส่วนตัวแล้วฉันชอบห่อโค้ดสคริปต์ทั้งหมดของฉันไว้ในฟังก์ชั่น "main" บางอย่างเช่น:

main () {
 echo running ...
}

# stuff ...

# calling the function at the very end of the script
time main

สังเกตว่าการใช้timeคำสั่งในสถานการณ์นี้ง่ายเพียงใด เห็นได้ชัดว่าคุณไม่ได้วัดเวลาที่แม่นยำรวมถึงเวลาในการแยกวิเคราะห์สคริปต์ แต่ฉันคิดว่ามันแม่นยำพอในสถานการณ์ส่วนใหญ่



1

ฟังก์ชั่นการจับเวลาตามSECONDSจำกัด เพียงระดับที่สองเท่านั้นไม่ใช้คำสั่งภายนอก:

time_it() {
  local start=$SECONDS ts ec
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Starting $*"
  "$@"; ec=$?
  printf -v ts '%(%Y-%m-%d_%H:%M:%S)T' -1
  printf '%s\n' "$ts Finished $*; elapsed = $((SECONDS-start)) seconds"
  # make sure to return the exit code of the command so that the caller can use it
  return "$ec"
}

ตัวอย่างเช่น:

time_it sleep 5

จะช่วยให้

2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished
sleep 5; elapsed = 5 seconds
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.