จะวัดเวลาดำเนินการเฉลี่ยของสคริปต์ได้อย่างไร


23

ฉันมีสองสคริปต์ที่แต่ละคนคำนวณแฟคทอเรียลของตัวเลข ฉันต้องการทราบว่าเร็วกว่าไหน timeคำสั่งให้ฉันมิลลิวินาทีและผลที่ได้จะแตกต่างจากเวลา:

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$ 

ฉันจะใช้เวลาเฉลี่ยในการรันสคริปต์ได้อย่างไร ฉันสามารถแยกและเอาท์พุทเฉลี่ยของ 100 timeแต่ฉันคิดว่ามีทางออกที่ดีกว่า?


คำตอบ:


4

ไม่ความคิดเรื่องค่าเฉลี่ยของคุณถูกต้อง

การเรียกใช้สคริปต์ขึ้นอยู่กับปัจจัยหลายอย่างและอย่างไรก็ตามจะต้องแยกระหว่างเวลาการตั้งค่า (โหลดล่ามในหน่วยความจำการตั้งค่าและอาจรวบรวมรหัสไปยัง bytecode หรือรหัสเครื่อง) และเวลาดำเนินการจริง

ในการมุ่งเน้นที่เวลาการดำเนินการภายในให้ดีขึ้นคุณทำวนรอบในสคริปต์เอง (เช่นแทนที่จะคำนวณหนึ่งแฟคทอเรียลคุณคำนวณได้ 100 ครั้งภายในการเรียกใช้สคริปต์หนึ่งครั้งสคริปต์จะถูกตั้งค่าหนึ่งครั้งและรูทีนด้านในจะดำเนินการ 100 ครั้ง)

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

เพื่อให้เข้าใจถึงอัลกอริทึมได้ดีขึ้นฉันคิดว่าวิธีที่ดีที่สุดคือสิ่งนี้ (บนเครื่องที่ไม่ได้ใช้งาน):

  • ห่ออัลกอริทึมในฟังก์ชั่นเดียว
  • ในแอปพลิเคชันควบคุม:
    • เรียกใช้ฟังก์ชันหนึ่งครั้ง
    • รับเวลาของระบบ ("นาฬิกาแขวนผนัง") และเพิ่ม 10 (หรือ N ที่เหมาะสม) วินาที
    • เข้าสู่วงและเริ่มนับซ้ำ
    • หลังจากการเรียกแต่ละครั้งไปยังฟังก์ชันให้เพิ่มตัวนับ
    • ถ้าเวลาของระบบต่ำกว่าเวลาที่บันทึกไว้ให้ทำลูปอื่น
    • รับ N แน่นอนซึ่งอาจเป็นจุดลอยตัวจากเวลานาฬิกาปัจจุบัน
    • แสดงตัวนับหารด้วย N: นั่นคือจำนวนการวนซ้ำ / วินาที

แอปพลิเคชั่นจะทำงานเพียงครั้งเดียวการตั้งค่าและการรองพื้นทั้งหมดจะทำโดยการวนซ้ำครั้งแรกดังนั้นจึงควรลดค่าใช้จ่ายให้น้อยที่สุด

หากฟังก์ชั่นรับอินพุตคุณควรระบุลำดับของอินพุตแบบสุ่มโดยใช้ค่า PRNG ที่มีค่าคงที่เพื่อให้แน่ใจว่าทั้งสองรุ่นของฟังก์ชันที่ทดสอบได้รับค่าเดียวกัน หลีกเลี่ยงหนึ่งฟังก์ชันที่ทำงานได้ดีกว่าเนื่องจาก "เลขนำโชค" (เช่นฉันจำการเปลี่ยนแปลงของอัลกอริทึม Hillsort ที่ทำหน้าที่วัดได้ดีกว่าถ้าจำนวนของรายการที่จะเรียงลำดับอยู่ในรูปแบบ 2 k -1 ที่มีkขนาดเล็ก)


ถูกต้องขอบคุณ ฉันสังเกตเห็นว่าสายที่ตามมาจะสั้นลง ฉันรันลูปภายในสคริปต์ตอนนี้และพบว่าอัลกอริทึมหนึ่งเร็วกว่าอีกแน่นอน
Victor Piousbox

39

คุณสามารถรันการวนซ้ำของโปรแกรมในลูป และหารเวลาทั้งหมดด้วยจำนวนการวนซ้ำ:

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

2
เรียบง่ายสุด ๆ รักมัน ฉันไม่เคยเห็นมา{1..10}ก่อนและงงงันว่ามันใช้งานไม่พบในคู่มือทุบตี สิ่งเดียวที่น่าเศร้าก็คือคุณไม่รู้การแพร่กระจายของผลลัพธ์ (นาทีและเวลาสูงสุด)
w00t

@ w00t:man -P 'less +/Brace\ Expansion' bash
2683246

ขอบคุณ @ user2683246! ฉันยังพบมันที่gnu.org/software/bash/manual/bash.html#Brace-Expansion - ใช้ btw น้อยกว่า ตอนนี้ฉันยังอยากรู้เกี่ยวกับเมื่อสิ่งนี้ปรากฏใน bash ...
w00t

1
Aha, รุ่น 3, 10 ปีหลังจากที่ฉันเริ่มใช้ bash :) tldp.org/LDP/abs/html/bashver3.html
w00t

2
ถ้าไม่ทำงานให้เดินทางมาถึงชาว Google bashก็อาจจะเป็นเพราะคุณไม่ได้ทำงาน ลองใช้/bin/bashก่อนหน้านี้
Cory Klein

14

มีเครื่องมือที่เรียกว่าmultitimeที่ทำสิ่งนี้: เรียกใช้คำสั่งหลายครั้ง, วัดระยะเวลาที่ใช้ (จริง / ผู้ใช้ / ระบบที่มีค่าเฉลี่ย, นาที / สูงสุดและเวลาเฉลี่ยคำนวณโดยอัตโนมัติ)

ตัวอย่างเช่นสำหรับการวัดสคริปต์ที่คล้ายกัน 100 ครั้ง:

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

นี่เก่า แต่มันสูงขึ้นมากใน google เมื่อฉันกำลังมองหาคำสั่งที่ฉันใช้ก่อนหน้านี้ แต่ไม่พบ อย่างไรก็ตามวิธีที่ฉันชอบในการทำเช่นนี้คือ:

perf stat -r 10 -B sleep 1

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

1.002248382 seconds time elapsed                   ( +-  0.01% )


1

Hyperfineเป็นอีกทางเลือกหนึ่ง

ตัวอย่างการใช้งาน:

hyperfine --warmup 3 'ruby fac1.rb'

1
ไฮเปอร์ไฟน์นั้นดีกว่าทางเลือกอื่น ๆ ที่ไร้สาระ การตรวจจับการวิ่ง, การอุ่นเครื่อง, เอาต์พุตที่สวยงาม, รายงาน markdown, การเขียนเป็นสนิม ฯลฯ
Klas Mellbourn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.