Làm cách nào để viết một điểm chuẩn vi mô chính xác trong Java?

Feb 03 2009

Làm thế nào để bạn viết (và chạy) một điểm chuẩn vi mô chính xác trong Java?

Tôi đang tìm kiếm một số mẫu mã và nhận xét minh họa nhiều điều khác nhau để suy nghĩ.

Ví dụ: Điểm chuẩn có nên đo thời gian / số lần lặp lại hay số lần lặp lại / thời gian và tại sao?

Liên quan: Điểm chuẩn của đồng hồ bấm giờ có được chấp nhận không?

Trả lời

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

Mẹo về cách viết điểm chuẩn vi mô từ những người tạo ra Java HotSpot :

Quy tắc 0: Đọc một bài báo có uy tín về JVM và điểm chuẩn vi mô. Một người tốt là Brian Goetz, 2005 . Đừng mong đợi quá nhiều từ các điểm chuẩn vi mô; chúng chỉ đo một phạm vi giới hạn của các đặc tính hiệu suất JVM.

Quy tắc 1: Luôn bao gồm giai đoạn khởi động chạy toàn bộ hạt nhân thử nghiệm của bạn, đủ để kích hoạt tất cả các lần khởi tạo và biên dịch trước (các) giai đoạn định thời. (Ít lặp lại hơn là OK trong giai đoạn khởi động. Quy tắc chung là vài chục nghìn lần lặp vòng lặp bên trong.)

Quy tắc 2: Luôn chạy với -XX:+PrintCompilation, -verbose:gcv.v., vì vậy bạn có thể xác minh rằng trình biên dịch và các phần khác của JVM không thực hiện công việc không mong muốn trong giai đoạn định thời của bạn.

Quy tắc 2.1: In thông báo ở đầu và cuối của giai đoạn định thời và khởi động, vì vậy bạn có thể xác minh rằng không có đầu ra từ Quy tắc 2 trong giai đoạn định thời.

Quy tắc 3: Nhận biết sự khác biệt giữa -client-server, và OSR và các biên dịch thông thường. Các -XX:+PrintCompilationcờ báo cáo biên soạn OSR với một ít-dấu hiệu để biểu thị điểm vào phi ban đầu, ví dụ: Trouble$1::run @ 2 (41 bytes). Ưu tiên máy chủ cho máy khách và thường xuyên sử dụng OSR, nếu bạn đang có hiệu suất tốt nhất.

Quy tắc 4: Lưu ý các hiệu ứng khởi tạo. Không in lần đầu tiên trong giai đoạn định thời của bạn, vì quá trình in sẽ tải và khởi tạo các lớp. Không tải các lớp mới bên ngoài giai đoạn khởi động (hoặc giai đoạn báo cáo cuối cùng), trừ khi bạn đang thử nghiệm tải lớp một cách cụ thể (và trong trường hợp đó, chỉ tải các lớp thử nghiệm). Quy tắc 2 là tuyến phòng thủ đầu tiên của bạn trước những tác động như vậy.

Quy tắc 5: Lưu ý về hiệu ứng khử khoáng và biên dịch lại. Không sử dụng bất kỳ đường dẫn mã nào lần đầu tiên trong giai đoạn định thời, vì trình biên dịch có thể rác và biên dịch lại mã, dựa trên giả định lạc quan trước đó rằng đường dẫn sẽ không được sử dụng. Quy tắc 2 là tuyến phòng thủ đầu tiên của bạn trước những tác động như vậy.

Quy tắc 6: Sử dụng các công cụ thích hợp để đọc suy nghĩ của trình biên dịch và mong đợi sẽ bị ngạc nhiên bởi mã mà nó tạo ra. Tự kiểm tra mã trước khi hình thành lý thuyết về điều gì làm cho thứ gì đó nhanh hơn hoặc chậm hơn.

Quy tắc 7: Giảm nhiễu trong các phép đo của bạn. Chạy điểm chuẩn của bạn trên một máy yên tĩnh và chạy nó nhiều lần, loại bỏ các điểm bất thường. Sử dụng -Xbatchđể tuần tự hóa trình biên dịch với ứng dụng và xem xét cài đặt -XX:CICompilerCount=1để ngăn trình biên dịch chạy song song với chính nó. Cố gắng hết sức để giảm chi phí GC, đặt Xmx(đủ lớn) bằng Xmsvà sử dụng UseEpsilonGCnếu nó có sẵn.

Quy tắc 8: Sử dụng thư viện cho điểm chuẩn của bạn vì nó có thể hiệu quả hơn và đã được gỡ lỗi cho mục đích duy nhất này. Chẳng hạn như JMH , Calibre hoặc Bill và Paul Các điểm chuẩn UCSD tuyệt vời cho Java .

244 AravindYarram Dec 19 2010 at 06:35

Tôi biết câu hỏi này đã được đánh dấu là đã trả lời nhưng tôi muốn đề cập đến hai thư viện giúp chúng tôi viết các điểm chuẩn vi mô

Calibre từ Google

Hướng dẫn bắt đầu

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

JMH từ OpenJDK

Hướng dẫn bắt đầu

  1. Tránh cạm bẫy đo điểm chuẩn trên JVM
  2. Sử dụng JMH cho Java Microbenchmarking
  3. Giới thiệu về JMH
88 JonSkeet Feb 03 2009 at 00:46

Những điều quan trọng đối với điểm chuẩn Java là:

  • Làm nóng JIT trước bằng cách chạy mã vài lần trước khi định thời gian cho
  • Đảm bảo bạn chạy nó đủ lâu để có thể đo kết quả trong vài giây hoặc (tốt hơn) hàng chục giây
  • Mặc dù bạn không thể gọi System.gc()giữa các lần lặp lại, nhưng bạn nên chạy nó giữa các lần kiểm tra, để mỗi lần kiểm tra hy vọng sẽ có được không gian bộ nhớ "sạch" để làm việc. (Đúng, gc()chỉ mang tính gợi ý hơn là đảm bảo, nhưng theo kinh nghiệm của tôi thì rất có thể nó sẽ thực sự thu gom rác.)
  • Tôi muốn hiển thị số lần lặp lại và thời gian cũng như điểm số của thời gian / lần lặp lại có thể được chia tỷ lệ sao cho thuật toán "tốt nhất" nhận được điểm 1,0 và các thuật toán khác được cho điểm theo cách tương đối. Điều này có nghĩa là bạn có thể chạy tất cả các thuật toán trong một thời gian dài, thay đổi cả số lần lặp lại và thời gian, nhưng vẫn nhận được kết quả có thể so sánh được.

Tôi chỉ đang viết blog về thiết kế khung đo điểm chuẩn trong .NET. Tôi đã có một vài các bài viết trước đây mà có thể cung cấp cho bạn một số ý tưởng - không mọi thứ sẽ thích hợp, tất nhiên, nhưng một số của nó có thể được.

48 assylias Apr 03 2013 at 19:32

jmh là một bổ sung gần đây cho OpenJDK và được viết bởi một số kỹ sư hiệu suất của Oracle. Chắc chắn đáng xem.

Jmh là một công cụ khai thác Java để xây dựng, chạy và phân tích các điểm chuẩn nano / vi mô / macro được viết bằng Java và các ngôn ngữ khác nhắm mục tiêu JVM.

Các mẩu thông tin rất thú vị bị chôn vùi trong các bài kiểm tra mẫu bình luận .

Xem thêm:

  • Tránh cạm bẫy đo điểm chuẩn trên JVM
  • Thảo luận về những điểm mạnh chính của jmh .
23 PeterLawrey Feb 03 2009 at 02:54

Điểm chuẩn có nên đo thời gian / lần lặp hay số lần lặp / thời gian không và tại sao?

Nó phụ thuộc vào những gì bạn đang cố gắng kiểm tra.

Nếu bạn quan tâm đến độ trễ , hãy sử dụng thời gian / lần lặp và nếu bạn quan tâm đến thông lượng , hãy sử dụng lần lặp / thời gian.

16 Kip Feb 03 2009 at 00:57

Nếu bạn đang cố gắng so sánh hai thuật toán, hãy thực hiện ít nhất hai điểm chuẩn cho mỗi thuật toán, xen kẽ thứ tự. I E:

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

Tôi đã tìm thấy một số khác biệt đáng chú ý (5-10% đôi khi) trong thời gian chạy của cùng một thuật toán ở các lần vượt qua khác nhau ..

Ngoài ra, hãy đảm bảo rằng n rất lớn, sao cho thời gian chạy của mỗi vòng lặp là ít nhất 10 giây hoặc lâu hơn. Càng nhiều lần lặp lại, càng có nhiều số liệu quan trọng trong thời gian chuẩn của bạn và dữ liệu đó càng đáng tin cậy.

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

Đảm bảo rằng bạn sử dụng bằng cách nào đó các kết quả được tính toán trong mã chuẩn. Nếu không, mã của bạn có thể được tối ưu hóa.

13 Mnementh Feb 03 2009 at 00:46

Có rất nhiều cạm bẫy có thể xảy ra khi viết các điểm chuẩn vi mô trong Java.

Đầu tiên: Bạn phải tính toán với tất cả các loại sự kiện mất thời gian ít nhiều ngẫu nhiên: Thu gom rác, hiệu ứng bộ nhớ đệm (của hệ điều hành đối với tệp và của CPU đối với bộ nhớ), IO, v.v.

Thứ hai: Bạn không thể tin tưởng vào độ chính xác của thời gian đo được trong những khoảng thời gian rất ngắn.

Thứ ba: JVM tối ưu hóa mã của bạn trong khi thực thi. Vì vậy, các lần chạy khác nhau trong cùng một phiên bản JVM sẽ ngày càng nhanh hơn.

Đề xuất của tôi: Làm cho điểm chuẩn của bạn chạy trong vài giây, điều đó đáng tin cậy hơn thời gian chạy trên mili giây. Làm nóng JVM (có nghĩa là chạy điểm chuẩn ít nhất một lần mà không cần đo, để JVM có thể chạy tối ưu hóa). Và chạy điểm chuẩn của bạn nhiều lần (có thể 5 lần) và lấy giá trị trung bình. Chạy mọi điểm chuẩn vi mô trong một phiên bản JVM mới (gọi mọi điểm chuẩn cho Java mới) nếu không các hiệu ứng tối ưu hóa của JVM có thể ảnh hưởng đến các bài kiểm tra đang chạy sau này. Không thực thi những thứ không được thực thi trong giai đoạn khởi động (vì điều này có thể kích hoạt tải lớp và biên dịch lại).

8 SpaceTrucker Jan 21 2013 at 21:04

Cũng cần lưu ý rằng việc phân tích kết quả của điểm chuẩn vi mô cũng rất quan trọng khi so sánh các cách triển khai khác nhau. Do đó, một kiểm định ý nghĩa nên được thực hiện.

Điều này là do việc triển khai Acó thể nhanh hơn trong hầu hết các lần chạy điểm chuẩn so với việc triển khai B. Nhưng Acũng có thể có mức chênh lệch cao hơn, vì vậy lợi ích hiệu suất đo được Asẽ không có ý nghĩa gì khi so sánh với B.

So it is also important to write and run a micro benchmark correctly, but also to analyze it correctly.

8 SinaMadani Mar 20 2017 at 02:21

To add to the other excellent advice, I'd also be mindful of the following:

For some CPUs (e.g. Intel Core i5 range with TurboBoost), the temperature (and number of cores currently being used, as well as thier utilisation percent) affects the clock speed. Since CPUs are dynamically clocked, this can affect your results. For example, if you have a single-threaded application, the maximum clock speed (with TurboBoost) is higher than for an application using all cores. This can therefore interfere with comparisons of single and multi-threaded performance on some systems. Bear in mind that the temperature and volatages also affect how long Turbo frequency is maintained.

Perhaps a more fundamentally important aspect that you have direct control over: make sure you're measuring the right thing! For example, if you're using System.nanoTime() to benchmark a particular bit of code, put the calls to the assignment in places that make sense to avoid measuring things which you aren't interested in. For example, don't do:

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

Problem is you're not immediately getting the end time when the code has finished. Instead, try the following:

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 - control tasks required to determine the comparative performance characteristics of the computer system on different platforms. Can be used to guide optimization decisions and to compare different Java implementations.