Mọi người cố gắng sử dụng khuôn khổ JMH để tạo một số xét nghiệm có ý nghĩa sẽ thấy các xét nghiệm mẫu JMH (http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/). Khi chúng tôi đi qua chúng, chúng tôi bị mắc kẹt bởi sự truy quét mã chết (JMHSample_08_DeadCode.java).Làm thế nào để loại bỏ mã chết Math.log() hoạt động trong mẫu JMH
Trích:
private double x = Math.PI;
@Benchmark
public void baseline() {
// do nothing, this is a baseline
}
@Benchmark
public void measureWrong() {
// This is wrong: result is not used, and the entire computation is optimized out.
Math.log(x);
}
Việc đo measureWrong() sẽ xấp xỉ như đối với các thử nghiệm cơ bản. Bởi vì giá trị trả về của Math.log() không bao giờ được sử dụng. Do đó trình biên dịch HotSpot sẽ loại bỏ mã chết. Ok, hiểu nhưng làm thế nào trình biên dịch có thể quyết định rằng Math.log() có thể được loại bỏ.
Khi chúng tôi xem xét kỹ thử nghiệm, chúng tôi lưu ý rằng Math.log() là một phương pháp gốc. Và các cuộc gọi bản địa đi xuống hệ điều hành và thực hiện một lib tương ứng. Đúng? Điều này dẫn chúng ta đến giả định rằng các cuộc gọi tự nhiên có thể bị loại bỏ bởi trình biên dịch nếu giá trị trả về của chúng không được sử dụng và chúng không thực hiện các hoạt động io.
Chúng tôi tự hỏi nếu lib nằm ở đâu đó trong hệ điều hành và xử lý cuộc gọi gốc từ thế giới java không cung cấp giá trị trả về nhưng thực hiện các thao tác io (ví dụ: ghi nhật ký). Các hướng dẫn đó có bị xóa hoàn toàn không?
Để chứng minh giả định của chúng tôi, chúng tôi đã xây dựng lại kịch bản bằng một bài kiểm tra JMH đơn giản và một cuộc gọi riêng. Chúng tôi biên soạn ba libs c-có nguồn gốc từ thực hiện:
- trở về 42
- tham số bổ sung
- tạo tập tin rỗng
Như chúng ta gọi chúng là trong một thử nghiệm JMH (tương tự như measureWrong() kiểm tra) không ai trong số họ đã được loại bỏ, thậm chí không phải là một trong đó không thực hiện một hoạt động io. Do kết quả thử nghiệm giả định của chúng tôi không thể được xác nhận. Các cuộc gọi bản địa không thể được tối ưu hóa, nghĩa là Math.log() và các cuộc gọi bản địa tùy chỉnh không có cùng cơ sở. Họ không phải là bản địa bình đẳng. Có lẽ chúng tôi đã phạm sai lầm trong mã lib gốc của chúng tôi và ít nhất là cuộc gọi bản địa của thử nghiệm 1 nên đã được eleminated. Nếu điều này đúng, chúng tôi sẽ chia sẻ mã của chúng tôi với bạn.
Vì vậy, chúng tôi đã tìm kiếm thêm và tìm thấy thuật ngữ Intrinsics nơi mã java sẽ được thay thế bằng mã số tương ứng với mã kiến trúc rất tối ưu. java.lang.Math.log() đang thực hiện nội tại như vậy. Có mối quan hệ nào giữa người bản địa và người bản xứ không? Nếu giả thuyết trên về mối quan hệ giữa người bản xứ và nội tại là hợp lệ thì trình biên dịch sẽ thực hiện các bước sau để loại bỏ cuộc gọi gốc?
- Tại thời điểm biên dịch, HotSpot kiểm tra sự tồn tại của thực thi nội tại (trong jdk?) Cho Math.log() và thay thế Math.log() bằng mã đó.
- Sau đó kiểm tra thứ hai xảy ra khi HotSpot xem xét sau giá trị trả lại của một phương thức. Và kết quả này, HotSpot quyết định loại bỏ hoàn toàn Math.log().
Math.log thực chất là một nội tại. Điều này có nghĩa là, nó được biết đến với JIT và được thay thế bằng một bộ hướng dẫn máy định sẵn. Ngoài ra, hướng dẫn bản địa không được loại bỏ bởi jit vì nó không thể chứng minh họ không có tác dụng phụ. Android vẫn có thể coi các phương pháp gốc của nó là nội tại. –