Bagaimana cara menulis tolok ukur mikro yang benar di Java?

Feb 03 2009

Bagaimana Anda menulis (dan menjalankan) benchmark mikro yang benar di Java?

Saya mencari beberapa contoh kode dan komentar yang menggambarkan berbagai hal untuk dipikirkan.

Contoh: Haruskah benchmark mengukur waktu / iterasi atau iterasi / waktu, dan mengapa?

Terkait: Apakah pembandingan stopwatch dapat diterima?

Jawaban

802 12revs,12users61%EugeneKuleshov Feb 05 2009 at 03:49

Kiat tentang menulis tolok ukur mikro dari pencipta Java HotSpot :

Aturan 0: Baca makalah terkemuka tentang JVM dan pembandingan mikro. Yang bagus adalah Brian Goetz, 2005 . Jangan berharap terlalu banyak dari tolok ukur mikro; mereka hanya mengukur rentang karakteristik kinerja JVM yang terbatas.

Aturan 1: Selalu sertakan fase pemanasan yang menjalankan kernel pengujian Anda sepenuhnya, cukup untuk memicu semua inisialisasi dan kompilasi sebelum fase waktu. (Lebih sedikit iterasi OK pada fase pemanasan. Aturan umumnya adalah beberapa puluh ribu iterasi loop dalam.)

Aturan 2: Selalu jalankan dengan -XX:+PrintCompilation,, -verbose:gcdll., Sehingga Anda dapat memverifikasi bahwa compiler dan bagian lain dari JVM tidak melakukan pekerjaan yang tidak diharapkan selama fase waktu Anda.

Aturan 2.1: Cetak pesan di awal dan akhir fase pengaturan waktu dan pemanasan, sehingga Anda dapat memverifikasi bahwa tidak ada keluaran dari Aturan 2 selama fase pengaturan waktu.

Aturan 3: Perhatikan perbedaan antara -clientdan -server, dan OSR dan kompilasi reguler. The -XX:+PrintCompilationbendera melaporkan kompilasi OSR dengan di-tanda untuk menunjukkan titik masuk non-awal, misalnya: Trouble$1::run @ 2 (41 bytes). Lebih suka server ke klien, dan biasa ke OSR, jika Anda menginginkan kinerja terbaik.

Aturan 4: Waspadai efek inisialisasi. Jangan mencetak untuk pertama kali selama fase waktu Anda, karena pencetakan memuat dan menginisialisasi kelas. Jangan memuat kelas baru di luar fase pemanasan (atau fase pelaporan akhir), kecuali Anda menguji pemuatan kelas secara khusus (dan dalam kasus tersebut hanya memuat kelas pengujian). Aturan 2 adalah garis pertahanan pertama Anda terhadap efek semacam itu.

Aturan 5: Waspadai deoptimization dan efek kompilasi ulang. Jangan mengambil jalur kode apa pun untuk pertama kalinya dalam fase waktu, karena kompilator mungkin membuang dan mengkompilasi ulang kode tersebut, berdasarkan asumsi optimis sebelumnya bahwa jalur tersebut tidak akan digunakan sama sekali. Aturan 2 adalah garis pertahanan pertama Anda terhadap efek semacam itu.

Aturan 6: Gunakan alat yang tepat untuk membaca pikiran penyusun, dan berharap akan terkejut dengan kode yang dihasilkannya. Periksalah kode itu sendiri sebelum membentuk teori tentang apa yang membuat sesuatu menjadi lebih cepat atau lambat.

Aturan 7: Kurangi noise dalam pengukuran Anda. Jalankan benchmark Anda pada mesin yang tidak berisik, dan jalankan beberapa kali, buang pencilan. Gunakan -Xbatchuntuk membuat serialisasi kompiler dengan aplikasi, dan pertimbangkan pengaturan -XX:CICompilerCount=1untuk mencegah kompilator berjalan secara paralel dengan dirinya sendiri. Cobalah yang terbaik untuk mengurangi overhead GC, setel Xmx(cukup besar) sama Xmsdan gunakan UseEpsilonGCjika tersedia.

Aturan 8: Gunakan pustaka untuk tolok ukur Anda karena mungkin lebih efisien dan sudah di-debug untuk satu-satunya tujuan ini. Seperti JMH , Caliper atau Bill dan Paul's Excellent UCSD Benchmarks for Java .

244 AravindYarram Dec 19 2010 at 06:35

Saya tahu pertanyaan ini telah ditandai sebagai terjawab tetapi saya ingin menyebutkan dua pustaka yang membantu kami menulis tolok ukur mikro

Caliper dari Google

Memulai tutorial

  1. http://codingjunkie.net/micro-benchmarking-with-caliper/
  2. http://vertexlabs.co.uk/blog/caliper

JMH dari OpenJDK

Memulai tutorial

  1. Menghindari Jebakan Tolok Ukur di JVM
  2. Menggunakan JMH untuk Java Microbenchmarking
  3. Pengantar JMH
88 JonSkeet Feb 03 2009 at 00:46

Hal-hal penting untuk tolok ukur Java adalah:

  • Pemanasan JIT pertama dengan menjalankan kode beberapa kali sebelum waktu itu
  • Pastikan Anda menjalankannya cukup lama untuk dapat mengukur hasil dalam hitungan detik atau (lebih baik) puluhan detik
  • Meskipun Anda tidak dapat memanggil System.gc()antar iterasi, sebaiknya jalankan di antara pengujian, sehingga setiap pengujian diharapkan mendapatkan ruang memori yang "bersih" untuk digunakan. (Ya, gc()ini lebih merupakan petunjuk daripada jaminan, tetapi sangat mungkin itu benar-benar akan mengumpulkan sampah menurut pengalaman saya.)
  • Saya suka menampilkan iterasi dan waktu, dan skor waktu / iterasi yang dapat diskalakan sedemikian rupa sehingga algoritme "terbaik" mendapat skor 1,0 dan lainnya dinilai secara relatif. Ini berarti Anda dapat menjalankan semua algoritme untuk waktu yang lama, memvariasikan jumlah iterasi dan waktu, tetapi tetap mendapatkan hasil yang sebanding.

Saya baru saja dalam proses membuat blog tentang desain kerangka kerja pembandingan di .NET. Aku punya beberapa dari posting sebelumnya yang mungkin dapat memberi Anda beberapa ide - tidak semuanya akan sesuai, tentu saja, tetapi beberapa mungkin.

48 assylias Apr 03 2013 at 19:32

jmh adalah tambahan terbaru untuk OpenJDK dan telah ditulis oleh beberapa insinyur kinerja dari Oracle. Layak untuk dilihat.

Jmh adalah harness Java untuk membangun, menjalankan, dan menganalisis tolok ukur nano / mikro / makro yang ditulis dalam Java dan bahasa lain yang menargetkan JVM.

Potongan informasi yang sangat menarik yang terkubur dalam komentar tes sampel .

Lihat juga:

  • Menghindari Jebakan Tolok Ukur di JVM
  • Diskusi tentang kekuatan utama jmh .
23 PeterLawrey Feb 03 2009 at 02:54

Haruskah tolok ukur mengukur waktu / iterasi atau iterasi / waktu, dan mengapa?

Itu tergantung pada apa yang Anda coba uji.

Jika Anda tertarik dengan latensi , gunakan waktu / iterasi dan jika Anda tertarik dengan throughput , gunakan iterasi / waktu.

16 Kip Feb 03 2009 at 00:57

Jika Anda mencoba membandingkan dua algoritme, lakukan setidaknya dua tolok ukur untuk masing-masing algoritme, bergantian urutan. yaitu:

for(i=1..n)
  alg1();
for(i=1..n)
  alg2();
for(i=1..n)
  alg2();
for(i=1..n)
  alg1();

Saya telah menemukan beberapa perbedaan yang mencolok (kadang-kadang 5-10%) dalam runtime dari algoritma yang sama pada lintasan yang berbeda ..

Juga, pastikan bahwa n sangat besar, sehingga waktu proses setiap loop paling sedikit 10 detik atau lebih. Semakin banyak iterasi, semakin banyak angka signifikan dalam waktu tolok ukur Anda dan semakin andal datanya.

15 PeterŠtibraný Feb 03 2009 at 01:00

Pastikan Anda menggunakan hasil yang dihitung dalam kode tolok ukur. Jika tidak, kode Anda dapat dioptimalkan.

13 Mnementh Feb 03 2009 at 00:46

Ada banyak kemungkinan kesulitan untuk menulis tolok ukur mikro di Java.

Pertama: Anda harus menghitung dengan semua jenis peristiwa yang memakan waktu kurang lebih acak: Pengumpulan sampah, efek cache (OS untuk file dan CPU untuk memori), IO, dll.

Kedua: Anda tidak dapat mempercayai keakuratan waktu yang diukur untuk interval yang sangat pendek.

Ketiga: JVM mengoptimalkan kode Anda saat dijalankan. Jadi, proses yang berbeda dalam instans JVM yang sama akan menjadi lebih cepat dan lebih cepat.

Rekomendasi saya: Jadikan benchmark Anda berjalan beberapa detik, itu lebih dapat diandalkan daripada runtime selama milidetik. Lakukan pemanasan JVM (artinya menjalankan benchmark setidaknya sekali tanpa mengukur, bahwa JVM dapat menjalankan pengoptimalan). Dan jalankan tolok ukur Anda beberapa kali (mungkin 5 kali) dan ambil nilai mediannya. Jalankan setiap tolok ukur mikro dalam instans JVM baru (panggilan untuk setiap tolok ukur Java baru) jika tidak, efek pengoptimalan JVM dapat memengaruhi pengujian yang dijalankan nanti. Jangan mengeksekusi sesuatu, yang tidak dieksekusi dalam fase pemanasan (karena ini dapat memicu pemuatan kelas dan kompilasi ulang).

8 SpaceTrucker Jan 21 2013 at 21:04

Perlu juga dicatat bahwa mungkin juga penting untuk menganalisis hasil dari benchmark mikro saat membandingkan implementasi yang berbeda. Oleh karena itu harus dilakukan uji signifikansi .

Ini karena implementasi Amungkin lebih cepat selama sebagian besar berjalannya benchmark daripada implementasi B. Tetapi Amungkin juga memiliki penyebaran yang lebih tinggi, sehingga manfaat kinerja yang diukur Atidak akan menjadi signifikan bila dibandingkan dengan B.

Jadi, penting juga untuk menulis dan menjalankan benchmark mikro dengan benar, tetapi juga menganalisisnya dengan benar.

8 SinaMadani Mar 20 2017 at 02:21

Untuk menambah saran bagus lainnya, saya juga akan memperhatikan hal-hal berikut:

Untuk beberapa CPU (misalnya kisaran Intel Core i5 dengan TurboBoost), suhu (dan jumlah core yang saat ini digunakan, serta persen pemanfaatannya) mempengaruhi kecepatan clock. Karena CPU memiliki waktu dinamis, ini dapat memengaruhi hasil Anda. Misalnya, jika Anda memiliki aplikasi single-threaded, kecepatan clock maksimum (dengan TurboBoost) lebih tinggi daripada aplikasi yang menggunakan semua core. Oleh karena itu, hal ini dapat mengganggu perbandingan performa single dan multi-threaded pada beberapa sistem. Ingatlah bahwa suhu dan volatilitas juga memengaruhi berapa lama frekuensi Turbo dipertahankan.

Mungkin aspek yang lebih fundamental penting yang dapat Anda kendalikan langsung: pastikan Anda mengukur hal yang benar! Misalnya, jika Anda menggunakan System.nanoTime()tolok ukur bit kode tertentu, letakkan panggilan ke tugas di tempat yang masuk akal untuk menghindari mengukur hal-hal yang tidak Anda minati. Misalnya, jangan lakukan:

long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");

Masalahnya adalah Anda tidak segera mendapatkan waktu akhir ketika kode telah selesai. Sebagai gantinya, coba yang berikut ini:

final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");
7 Yuriy Dec 19 2010 at 06:22

http://opt.sourceforge.net/Java Micro Benchmark - tugas kontrol yang diperlukan untuk menentukan karakteristik kinerja komparatif dari sistem komputer pada platform yang berbeda. Dapat digunakan untuk memandu keputusan pengoptimalan dan untuk membandingkan implementasi Java yang berbeda.