Bagaimana cara mengukur rata-rata waktu eksekusi suatu skrip?

23

Saya memiliki dua skrip yang masing-masing menghitung faktorial angka. Saya ingin tahu mana yang lebih cepat. The timeperintah memberi saya milidetik dan hasilnya berbeda dari waktu ke waktu:

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$ 

Bagaimana saya mengambil waktu rata-rata yang diperlukan untuk menjalankan skrip? Saya dapat mengurai dan rata - rata keluaran 100 time- an tapi saya membayangkan ada solusi yang lebih baik?

Victor Piousbox
sumber
1
stackoverflow.com/questions/8215482/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

4

Tidak, ide Anda tentang rata-rata sudah benar.

Eksekusi skrip tergantung pada banyak faktor, dan bagaimanapun harus dibagi antara waktu setup (memuat interpreter dalam memori, pengaturan, dan mungkin mengkompilasi kode untuk bytecode atau kode mesin) dan waktu eksekusi yang sebenarnya.

Untuk lebih fokus pada waktu eksekusi dalam, Anda melakukan loop dalam skrip itu sendiri (yaitu alih-alih menghitung satu faktorial, Anda menghitungnya 100 kali dalam satu kali eksekusi skrip. Skrip akan diatur sekali, dan rutinitas dalam akan mengeksekusi 100 waktu).

Untuk fokus pada total waktu, Anda menjalankan skrip seratus kali dan rata-rata hasilnya. Idealnya, Anda harus memisahkan eksekusi tersebut cukup sehingga sistem kembali dalam "keadaan referensi" (atau keadaan tidak terkait skrip) setiap kali. Sebagai contoh, juru itu sendiri akan di-cache dalam memori, sehingga pertama pelaksanaan script akan lumayan lambat dari yang berikutnya.

Untuk mendapatkan wawasan yang lebih baik tentang algoritme, saya pikir cara terbaik adalah sesuatu seperti ini (pada mesin idle):

  • bungkus algoritme dalam satu fungsi tunggal.
  • dalam aplikasi pengendali:
    • panggil fungsi sekali
    • dapatkan waktu sistem ("jam dinding") dan tambahkan 10 (atau N masuk akal) detik
    • masukkan loop dan mulai menghitung iterasi
    • setelah setiap panggilan ke fungsi, tambahkan penghitung
    • jika waktu sistem di bawah waktu yang disimpan, lakukan perulangan lagi
    • dapatkan N yang tepat, mungkin titik mengambang, dari waktu jam dinding saat ini
    • tampilkan penghitung dibagi dengan N: itu adalah jumlah iterasi / detik.

Aplikasi hanya berjalan sekali, semua pengaturan dan pemasangan dilakukan oleh iterasi tanpa batas waktu pertama, jadi ini harus meminimalkan overhead (kecuali mungkin untuk panggilan waktu).

Jika fungsi menerima input, Anda sebaiknya menyediakannya urutan acak input menggunakan PRNG yang diunggulkan dengan nilai tetap, untuk memastikan kedua versi fungsi yang diuji menerima nilai yang sama. Ini menghindari satu fungsi yang tampaknya lebih baik karena "angka keberuntungan" (mis. Saya ingat variasi algoritma Hillsort yang berkinerja lebih baik jika jumlah item yang akan diurutkan dalam bentuk 2 k -1 dengan k kecil ).

LSerni
sumber
Benar, terima kasih. Saya perhatikan bahwa panggilan selanjutnya menjadi semakin pendek. Saya menjalankan loop di dalam skrip sekarang, dan menemukan bahwa satu algoritma pasti lebih cepat daripada yang lain.
Victor Piousbox
39

Anda dapat menjalankan iterasi program dalam satu lingkaran; dan bagi total waktu dengan jumlah iterasi:

time for i in {1..10}; do sleep 1; done
real    0m10.052s
user    0m0.005s
sys 0m0.018s
Kent
sumber
2
Sangat sederhana, cinta itu. Saya juga tidak pernah melihat {1..10}sebelumnya dan saya bingung bahwa itu berhasil, tidak dapat menemukannya di manual bash. Satu-satunya hal yang menyedihkan adalah Anda tidak tahu penyebaran hasil Anda (waktu minimum dan maksimum).
w00t
@ w00t:man -P 'less +/Brace\ Expansion' bash
user2683246
Terima kasih @ user2683246! Saya kemudian juga menemukannya di gnu.org/software/bash/manual/bash.html#Brace-Expansion - penggunaan btw kurang bagus. Sekarang saya juga ingin tahu tentang kapan ini muncul di bash ...
w00t
1
Aha, versi 3, 10 tahun setelah saya mulai menggunakan bash :) tldp.org/LDP/abs/html/bashver3.html
w00t
2
Jika ini tidak berfungsi untuk kedatangan Google, mungkin karena Anda tidak menjalankan bash. Coba jalankan /bin/bashsebelum ini.
Cory Klein
14

ada alat yang disebut multitime yang melakukan hal ini: menjalankan perintah beberapa kali, mengukur berapa lama (real / user / sistem dengan rata-rata, min / maks, dan waktu rata-rata dihitung secara otomatis)

Misalnya, untuk mengukur skrip serupa 100 kali:

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 
Cyril Chaboisseau
sumber
12

Ini sudah lama tetapi muncul sangat tinggi di google ketika saya mencari perintah yang saya gunakan sebelumnya tetapi tidak dapat menemukan. Bagaimanapun, cara pilihan saya untuk melakukan ini adalah:

perf stat -r 10 -B sleep 1

Ini memberikan sedikit detail termasuk waktu eksekusi rata-rata tepat di akhir:

1.002248382 seconds time elapsed                   ( +-  0.01% )
Zaahid
sumber
1

Hyperfine adalah pilihan lain.

Penggunaan sampel:

hyperfine --warmup 3 'ruby fac1.rb'
Luís Bianchin
sumber
1
hyperfine jauh lebih baik daripada alternatif lain yang konyol. Deteksi jalan diperlukan, pemanasan, hasil indah, laporan penurunan harga, ditulis dalam karat, dll
Klas Mellbourn