2012-04-11 23 views
31

Gần đây tôi đã phát hiện ra rằng người ta có thể sử dụng JIT (chỉ trong thời gian) biên dịch với R bằng cách sử dụng gói trình biên dịch (tôi tóm tắt những phát hiện của tôi về chủ đề này trong a recent blog post).Những thiếu sót có thể xảy ra khi sử dụng JIT với R?

Một trong những câu hỏi tôi đã hỏi là:

Có bất kỳ cạm bẫy? nó có vẻ quá tốt là đúng, chỉ cần đặt một dòng mã và đó là nó.

Sau khi tìm kiếm xung quanh, tôi có thể tìm thấy một vấn đề có thể xảy ra với thời gian "khởi động" cho JIT. Nhưng có vấn đề gì khác phải cẩn thận khi sử dụng JIT?

Tôi đoán rằng sẽ có một số hạn chế phải làm với kiến ​​trúc môi trường của R, nhưng tôi không thể nghĩ ra một minh hoạ đơn giản của vấn đề trên đầu của tôi, bất kỳ gợi ý hoặc cờ đỏ sẽ được giúp đỡ rất nhiều?

+0

Tôi không chắc chắn về các lần truy cập hiệu suất (ngoài biên dịch ban đầu (và có thể tăng mức sử dụng bộ nhớ)) nhưng thông báo "Lưu ý: không nhìn thấy được" thường có thể áp đảo đối với người mới (ví dụ: nếu sử dụng ggplot2) và có thể vứt bỏ hoàn thành tab (ít nhất, chúng dành cho tôi) – mweylandt

+0

Xin chào mweylandt. Bạn có biết điều massage đó có nghĩa là gì không? –

+4

Tôi đã đặt 'ByteCompile: true' trong tệp DESCRIPTION của các gói của mình khi tạo các phiên bản mới và có vẻ như nó hoạt động tốt. Tôi đã làm một thử nghiệm nhỏ 'http: // www.johnmyleswhite.com/notebook/2012/03/31/julia-i-love-bạn/comment-page-1/# comment-19522' và phiên bản được biên dịch byte,' fib2c' chạy nhanh gấp 4 lần so với thông thường, 'fib2a'. Trong một số trường hợp R đã nhanh ngay cả khi không biên dịch byte (ví dụ: mã vectơ hóa cao sử dụng C bên dưới) và trong những trường hợp đó rõ ràng là ít cơ hội để tăng tốc - chủ yếu là hữu ích cho mã R chậm. –

Trả lời

4

Các rpart dụ đưa ra ở trên, không còn có vẻ là một vấn đề:

library("rpart") 
fo = function() { 
    for(i in 1:500){ 
    rpart(Kyphosis ~ Age + Number + Start, data=kyphosis) 
    } 
} system.time(fo()) 
# user system elapsed 
# 1.212 0.000 1.206 
compiler::enableJIT(3) 
# [1] 3 
system.time(fo()) 
# user system elapsed 
# 1.212 0.000 1.210 

Tôi cũng đã thử một số ví dụ khác, chẳng hạn như

  • phát triển một vector;
  • Một chức năng đó chỉ là một wrapper quanh mean

Trong khi tôi không luôn có được một tốc độ lên, tôi chưa bao giờ trải nghiệm một ý nghĩa chậm xuống.


R> sessionInfo() 
R version 3.3.0 (2016-05-03) 
Platform: x86_64-pc-linux-gnu (64-bit) 
Running under: Ubuntu 16.04 LTS 
11

sản phẩm của một thử nghiệm đơn giản với rpart có thể là một lời khuyên không sử dụng enableJIT trong mọi trường hợp:

library(rpart) 
fo <- function() for(i in 1:500){rpart(Kyphosis ~ Age + Number + Start, data=kyphosis)} 
system.time(fo()) 
#User  System verstrichen 
#2.11  0.00  2.11 

require(compiler) 
enableJIT(3) 
system.time(fo()) 
#User  System verstrichen 
#35.46  0.00  35.60 

Bất kỳ explanantion?

+1

Điều đó thật kỳ quặc, vì vậy một điều gì đó về bye biên dịch vòng lặp trong fo đang gây ra vấn đề. Nếu bạn biên dịch nó bình thường thì nó sẽ không xảy ra. http://ideone.com/Nu8IZ, chú thích rpart đã được biên dịch theo byte. – Hansi

+7

Biên dịch mất một nửa phút tốt: Tôi thấy như vậy (2,8 s - 42,6 s), nhưng sau đó làm system.time (fo()) lại chỉ mất 2,6 s. – cbeleites

+1

Tôi nghi ngờ rằng đây là một hành vi không mong muốn ... –

-2

Ngoài câu trả lời trước, thử nghiệm cho thấy sự cố là không phải là với việc biên dịch vòng lặp, đó là việc biên dịch bao đóng. [enableJIT (0) hoặc enableJIT (1) để lại mã nhanh, enableJIT (2) làm chậm tốc độ, và enableJIT (3) hơi nhanh hơn tùy chọn trước (nhưng vẫn rất chậm)]. Ngoài ra trái với bình luận của Hansi, cmpfun làm chậm thực hiện đến một mức độ tương tự.

+0

Có vẻ như rõ ràng lý do cho các kết quả khác nhau là các phiên bản khác nhau của R. Sử dụng R 3.3.2 ngày hôm nay, enableJIT (i) cho chính xác cùng một thời điểm (1,21 giây) bất kể tôi là 0, 1, 2 hay 3. Tôi sẽ để lại lời giải thích cho người khác, nhưng thông báo cho tôi là nó được tối ưu hóa mà không cần bất kỳ trợ giúp từ người dùng ngay bây giờ. – Elroch

0

Về nguyên tắc, một khi byte-code được biên soạn và được nạp, nó nên luôn luôn được hiểu ít nhất nhanh như thông dịch viên AST gốc. Một số mã sẽ được hưởng lợi từ việc tăng tốc lớn, thường là mã với rất nhiều hoạt động vô hướng và vòng lặp mà hầu hết thời gian được giải thích R (tôi đã xem các ví dụ với tốc độ gấp 10 lần nhưng các tiêu chuẩn vi mô tùy ý thực sự có thể thổi phồng khi cần). Một số mã sẽ chạy ở cùng một tốc độ, điều này thường được mã hóa vectơ và do đó chi tiêu gần như không có thời gian để giải thích. Bây giờ, việc biên dịch có thể chậm. Do đó, trình biên dịch ngay trong thời gian hiện tại không biên dịch các chức năng khi nó đoán nó sẽ không trả hết (và sự thay đổi heuristics theo thời gian, điều này đã có trong 3.4.x). Các chẩn đoán không phải lúc nào cũng đoán đúng, vì vậy có thể có các tình huống khi biên dịch sẽ không trả hết. Các mẫu có vấn đề điển hình là tạo mã, sửa đổi mã và thao tác các ràng buộc của các môi trường được chụp trong các bao đóng.

Các gói có thể được biên dịch byte tại thời điểm cài đặt sao cho chi phí biên dịch không được thanh toán (nhiều lần) tại thời gian chạy, ít nhất là đối với mã được biết trước. Điều này bây giờ là mặc định trong phiên bản phát triển của R. Trong khi việc tải mã được biên dịch nhanh hơn nhiều so với biên dịch nó, trong một số trường hợp, một số có thể tải ngay cả mã sẽ không được thực thi. biên dịch trước là có lợi. Gần đây một số thông số của GC đã được điều chỉnh để giảm chi phí tải mã sẽ không được thực hiện.

Đề xuất của tôi cho các nhà văn gói sẽ sử dụng các giá trị mặc định (biên dịch theo thời gian hiện được bật theo mặc định trong các phiên bản đã phát hành, thời gian cài đặt gói hiện có trong phiên bản phát triển). Nếu bạn tìm thấy một ví dụ trong đó trình biên dịch mã byte không hoạt động tốt, vui lòng gửi báo cáo lỗi (tôi cũng đã thấy một trường hợp liên quan đến rpart trong các phiên bản trước đó). Tôi sẽ khuyên bạn nên chống lại việc tạo mã và thao tác mã và đặc biệt trong các vòng lặp nóng. Điều này bao gồm việc xác định các bao đóng, xóa và chèn các ràng buộc trong các môi trường được chụp bởi các bao đóng. Chắc chắn người ta không nên làm eval(parse(text= trong các vòng lặp nóng (và điều này đã xấu mà không có biên dịch byte). Nó luôn luôn là tốt hơn để sử dụng các chi nhánh hơn để tạo ra đóng cửa mới (không có chi nhánh) tự động. Ngoài ra nó là tốt hơn để viết mã với vòng hơn để tự động tạo mã với các biểu thức rất lớn (không có vòng). Bây giờ với trình biên dịch mã byte, bây giờ thường là ok để viết các vòng hoạt động trên vô hướng trong R (hiệu năng sẽ không tệ như trước, vì vậy người ta thường có thể thoát khỏi mà không cần chuyển sang C cho các phần quan trọng về hiệu năng) .

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