2009-02-02 45 views
21

Tôi thấy trên Internet mà tôi được cho là sử dụng System.nanoTime() nhưng điều đó không hiệu quả đối với tôi - nó mang lại cho tôi thời gian với độ chính xác mili giây. Tôi chỉ cần micro giây trước và sau khi chức năng của tôi thực hiện để tôi biết phải mất bao lâu. Tôi đang sử dụng Windows XP.Làm thế nào tôi có thể đo thời gian với độ chính xác micro giây trong Java?

Về cơ bản, tôi có mã này, ví dụ, thực hiện 1 triệu đến 10 triệu lần chèn trong một danh sách liên kết java. Vấn đề là tôi không thể đo được độ chính xác; đôi khi phải mất ít thời gian hơn để chèn mọi thứ vào danh sách nhỏ hơn.

Dưới đây là một ví dụ:

class test 
{ 
    public static void main(String args[]) 
    { 
     for(int k=1000000; k<=10000000; k+=1000000) 
     { 
      System.out.println(k); 
      LinkedList<Integer> aux = new LinkedList<Integer>(); 
      //need something here to see the start time 
      for(int i=0; i<k; i++) 
       aux.addFirst(10000); 
      //need something here to see the end time 
      //print here the difference between both times 
     } 
    } 
} 

Tôi đã làm điều này nhiều lần - có một vòng lặp bên ngoài làm nó 20 lần cho mỗi k - nhưng kết quả không tốt. Đôi khi phải mất ít thời gian hơn để thực hiện 10 triệu lần chèn hơn 1 triệu, bởi vì tôi không nhận được thời gian đo chính xác với những gì tôi đang sử dụng bây giờ (System.nanoTime())

Chỉnh sửa 2: Có, tôi ' m bằng cách sử dụng Sun JVM.

Chỉnh sửa 3: Tôi có thể đã làm điều gì đó sai trong mã, tôi sẽ xem nếu thay đổi nó làm những gì tôi muốn.

Chỉnh sửa 4: Lỗi của tôi, có vẻ như System.nanoTime() hoạt động. Phew.

+0

Phiên bản Java nào? Trên máy XP của tôi w/JDK1.6.0_06, nanoTime() có độ chính xác thông qua các vị trí thập phân cuối cùng. Tôi giả sử phiên bản của bạn trả về các giá trị luôn luôn kết thúc bằng ba số không. – basszero

+0

Sun JVM là không đủ, VERSION của nó? (Câu trả lời của bạn là chính xác, tôi không hỏi 'câu hỏi đúng. Tôi giả định mọi người sử dụng Sun JVM) – basszero

+0

Java -version trong cmd cho tôi: phiên bản java "1.7.0-ea" Và 2 dòng khác. Dù bằng cách nào, đó là một sai lầm trong mã của tôi. Rất tiếc, tôi không thể tìm thấy lỗi ngay cả sau một lúc tìm kiếm. –

Trả lời

24

Nó không rõ ràng với tôi chính xác những gì bạn đang benchmark, nhưng nói chung bất kỳ thử nghiệm mà mất như một khoảng thời gian ngắn để chạy, mà độ chính xác thấp hơn 50 ms là có liên quan, sẽ là rất dễ bị rối loạn khác.

Tôi thường cố gắng tạo điểm chuẩn chạy trong ít nhất 10 giây. Khung tôi đang viết tại thời điểm này sẽ đoán có bao nhiêu lần lặp lại để chạy sẽ mất 30 giây. Điều đó có nghĩa là bạn sẽ không nhận được hoàn toàn kết quả khác nhau chỉ vì một số quy trình khác đã lấy cắp CPU trong vài phần nghìn giây.

Chạy lâu hơn hầu như luôn là cách tiếp cận tốt hơn so với cố gắng đo lường với độ chính xác chi tiết hơn.

3

Thật kỳ lạ. System.nanoTime() là nghĩa vụ phải làm việc. Bạn đang sử dụng Sun JVM?

Bạn có thể lặp lại hoạt động của mình 1000 lần và chia thời gian cho 1000 để tìm hiểu những gì bạn cần biết không?

3

Bạn phải lặp lại các bài kiểm tra hàng ngàn lần. Có rất nhiều điều xảy ra sẽ ảnh hưởng đến số đo của bạn, như thu thập rác, I/O, hoán đổi vào/ra, kích thước của các chủ đề hàng đợi sẵn sàng, v.v.

30

Tôi đoán là vì System.nanoTime() sử dụng "chính xác nhất bộ đếm thời gian hệ thống có sẵn "mà dường như chỉ có độ chính xác mili giây trên hệ thống của bạn, bạn không thể nhận được bất kỳ thứ gì tốt hơn.

1

Có thể trường hợp hệ điều hành bên dưới không cung cấp bộ tính giờ có độ chính xác nano giây.

Ngoài ra còn có older post.

0

Điểm chuẩn như vậy dựa trên khoảng thời gian ngắn cho bạn kết quả không đáng tin cậy. Bạn sẽ luôn nhận được các kết quả khác nhau, bởi vì các yếu tố bên ngoài như I/O, Hoán đổi, Quy trình chuyển mạch, Bộ nhớ cache, Bộ sưu tập rác vvNgoài ra, JVM tối ưu hóa các cuộc gọi của bạn, vì vậy có khả năng những thứ đo đầu tiên sẽ chậm hơn cuộc gọi sau. JVM bắt đầu ngày càng nhiều để tối ưu hóa các lệnh bạn thực hiện.

Ngoài ra, phương thức như System.nanoTime() phụ thuộc vào bộ tính giờ của hệ thống cơ bản. Họ có thể (và rất có thể sẽ) không có độ chi tiết để đo lường chính xác. Để trích dẫn API:

Phương pháp này cung cấp nano giây chính xác, nhưng không nhất thiết chính xác nano giây. Không có đảm bảo nào là về tần suất giá trị thay đổi.

Để thực sự đo với độ chính xác cao, bạn cần truy cập phần cứng thời gian bên ngoài với độ chính xác được đảm bảo.

Để làm cho điểm chuẩn của bạn ổn định hơn, bạn cần phải thực hiện nhiều lần và để đo khoảng thời gian lớn hơn chỉ một phần nghìn giây.

4

System.nanoTime() sử dụng bộ đếm trong CPU và thường chính xác khoảng 1 micro giây trên Windows XP và Linux.

Lưu ý: Windows XP thường kém chính xác hơn trên các máy đa CPU vì nó không bù cho các CPU khác nhau có các bộ đếm khác nhau. Linux. Lưu ý 2: Nó sẽ trôi dạt tương đối so với System.currentTimeMillis() vì nó dựa trên độ chính xác của đồng hồ cho CPU của bạn (không cần phải chính xác trong một khoảng thời gian), thay vì đồng hồ (để giảm thời gian mỗi ngày, nhưng ít chi tiết hơn)

Trong tiêu chuẩn của bạn, về cơ bản bạn đang thử nghiệm tốc độ mà tại đó bạn có thể tạo các đối tượng mới. Không ngạc nhiên khi kết quả của bạn sẽ thay đổi đáng kể dựa trên các thiết lập GC của bạn và gần đây GC được thực hiện như thế nào.

Thử chạy thử nghiệm của bạn với các tùy chọn sau và bạn sẽ thấy kết quả rất khác.

-verbosegc -XX: NewSize = 128 -mx256m

2

Nếu bạn muốn có một kết quả đáng tin cậy, sử dụng một hồ sơ. Tôi đề nghị VisualVM, dễ cài đặt và được đóng gói với JDK bắt đầu từ phiên bản 1.6.0_07. Công cụ trực quan dễ sử dụng tích hợp một số công cụ JDK dòng lệnh và khả năng lược tả nhẹ.

1

Có, độ chính xác và chính xác của System.nanoTime thường tốt hơn nhiều so với System.currentTimeMillis, nhưng không đảm bảo: nó có thể trở nên tồi tệ trong trường hợp xấu nhất.

ThreadMXBean.getCurrentThreadCpuTime có xu hướng mang lại thời gian nhỏ hơn, nhưng độ phân giải của nó không rõ ràng và có nhiều nhược điểm hơn (bạn có thực sự muốn thời gian CPU ?, ngữ nghĩa phụ thuộc nền tảng, được hỗ trợ trên nền tảng của bạn không?).

Đo thời gian với cả ba kỹ thuật cũng có một số chi phí, tức là yêu cầu thời gian, có thể bóp méo các phép đo. Chi phí phụ thuộc nhiều vào nền tảng, nhưng thường chi phí (System.currentTimeMillis) < < chi phí (System.nanoTime) < < chi phí (ThreadMXBean.getCurrentThreadCpuTime).

Về điểm chuẩn micro nói chung, xem

0

một "nhanh chóng và dơ bẩn" giải pháp mà tôi cuối cùng đã đi với:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime()); 

UPDATE:

tôi ban đầu đã đi với System.nanoTime nhưng sau đó tôi phát hiện ra nó chỉ nên được sử dụng cho thời gian trôi qua, tôi cuối cùng đã thay đổi mã của tôi để làm việc với mili giây hoặc tại một số nơi sử dụng:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); 

nhưng điều này sẽ chỉ thêm số không vào cuối giá trị (phần triệu = millis * 1000)

Left câu trả lời này ở đây như là một "dấu hiệu cảnh báo" trong trường hợp người khác nghĩ về nanoTime :)

0

Đối với hồ sơ của chúng tôi gần đây, tôi thấy rằng ThreadMXBean.getCurrentThreadCpuTime() và tùy chọn -XX: + UseLinuxPosixThreadCPUClocks đã làm gì chúng tôi cần.

Xem http://bugs.java.com/view_bug.do?bug_id=6888526 để biết thêm chi tiết

3

Sử dụng java.time

FYI, Java 9 và sau đó có thực hiện trong lành của Clock có thể nắm bắt những khoảnh khắc hiện tại lên đến độ phân giải nano giây.

Lớp Instant đại diện cho một thời điểm trên dòng thời gian ở UTC với độ phân giải nanoseconds (tối đa chín (9) chữ số thập phân).

Gọi Instant.now để ghi lại khoảnh khắc hiện tại.

  • Trong Java 9 trở lên, bạn có độ phân giải tối đa nanoseconds cho thời điểm hiện tại.
  • Trong Java 8, thời điểm hiện tại được chụp chỉ lên đến độ phân giải milliseconds (bạn có thể thực sự giữ giá trị với nano giây, nhưng chỉ chụp thời điểm hiện tại trong mili giây).

    Instant tức thì = Instant.now();

Đại diện cho khoảng thời gian không được gắn với dòng thời gian với Duration lớp. Giữ một lượng thời gian tính bằng giây và nano giây.

Duration d = Duration.between(instantThen , Instant.now()); 

Để được rõ ràng, độ phân giải microseconds hỏi trong câu hỏi là ở giữa granularities mili giây và nano giây. Số lượng vị trí trong một phần thập phân: millis là 3 (0.123), micros là 6 (0.123456), nanos là 9 (0.123456789).

caveat

Java dựa vào đồng hồ phần cứng của máy tính. Như những người khác đã cảnh báo, phần cứng đó hầu như chắc chắn sẽ thu được thời gian với độ chính xác kém hơn ít hơnđộ phân giải thấp hơn hơn nano giây.

Đo điểm chuẩn ở mức độ chi tiết cao như vậy là đầy vấn đề và không khuyến khích thường là.

Và hãy cẩn thận với premature optimization.

Có đề xuất thêm cơ sở đo điểm chuẩn vi mô vào nền tảng Java trong JEP 230: Microbenchmark Suite. Dựa trên số Java Microbenchmark Harness (JMH).


Về java.time

Khung java.time được xây dựng vào Java 8 và sau đó. Các lớp này thay thế các lớp học ngày giờ legacy phiền hà cũ như java.util.Date, Calendar, & SimpleDateFormat.

Dự án Joda-Time, hiện đang ở maintenance mode, khuyên di chuyển đến các lớp java.time.

Để tìm hiểu thêm, hãy xem Oracle Tutorial. Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310.

Nơi lấy các lớp java.time?

Dự án mở rộng ThreeTen-Extra java.time với các lớp bổ sung. Dự án này là một nền tảng chứng minh cho những bổ sung có thể có trong tương lai vào java.time.Bạn có thể tìm thấy một số lớp học hữu ích tại đây như Interval, YearWeek, YearQuartermore.

Các vấn đề liên quan