2015-06-01 16 views
7

xem xét ví dụ tối thiểu sau đây:cython boundscheck = True nhanh hơn boundscheck = False

#cython: language_level=3, boundscheck=False, wraparound=False, initializedcheck=False, cdivision=True 
cimport cython 
from libc.stdlib cimport malloc 

def main(size_t ni, size_t nt, size_t nx): 
    cdef: 
     size_t i, j, t, x, y 
     double[:, :, ::1] a = <double[:ni, :ni, :nx]>malloc(ni * ni * nx * sizeof(double)) 
     double[:, :, ::1] b = <double[:nt, :ni, :nx]>malloc(nt * ni * nx * sizeof(double)) 
     size_t[:, :, ::1] best = <size_t[:nt, :ni, :nx]>malloc(nt * ni * nx * sizeof(size_t)) 
     size_t mxi 
     double s, mxs 
    for t in range(nt): 
     for j in range(ni): 
      for y in range(nx): # this loops does nothing but is needed for the effect below. 
       mxs = -1e300 
       for i in range(ni): 
        for x in range(nx): 
         with cython.boundscheck(False): # Faster!?!? 
          s = b[t, i, x] + a[i, j, x] 
         if s >= mxs: 
          mxs = s 
          mxi = i 
       best[t + 1, j, y] = mxi 
    return best[0, 0, 0] 

cơ bản tổng hợp hai mảng 2D cùng một số trục cụ thể và tìm ra các chỉ số tối đa hóa dọc theo trục khác.

Khi được biên dịch bằng gcc -O3 và được gọi với các đối số (1, 2000, 2000), hãy thêm boundscheck = Kết quả thực trong thực thi nhanh hơn gấp hai lần khi boundscheck = False.

Bất kỳ gợi ý nào về lý do này sẽ xảy ra? (Ừm, tôi có thể đoán điều này một lần nữa để làm với tự động hóa GCC ...)

Xin cảm ơn trước.

(cross-đăng từ cython-users)

+1

Trong các thử nghiệm của tôi, các phiên bản với 'với cython.boundscheck (True)' là chậm hơn khoảng 3 lần. Tôi nghĩ rằng bộ nhớ cho 'a',' b', 'best' là tất cả uninitialized vì' malloc'. Tôi đã thay đổi điều đó thành một cuộc gọi 'calloc' tương đương. Ngoài ra, dòng 'tốt nhất [t + 1, j, y]' dường như đang lập chỉ mục bộ nhớ không hợp lệ khi 't == nt - 1'. –

+0

Thay đổi mallocs thành callocs và thay thế 't + 1' bằng' t' không (chất lượng) thay đổi kết quả cho tôi. 'Setup.py' của tôi có' extra_compile_args = ["- O3"] 'và tôi đang sử dụng gcc 5.1.0. – antony

+1

OK, tôi đã thử với -O3 và tôi nhận được cùng một tốc độ với cả hai phiên bản. Tôi đang sử dụng gcc 4.9.1. Nhìn vào mã C được tạo ra, tôi nghĩ có thể gcc đủ thông minh để biết rằng các kiểm tra giới hạn bổ sung sẽ không bao giờ được kích hoạt (vì điều kiện vòng lặp). Tôi không biết tại sao bạn nhận được tốc độ khác nhau như vậy mặc dù. –

Trả lời

-1

Boundscheck là một kiểm tra an ninh mà bạn đang truy cập vào các chỉ số bên bờ cõi của các vectơ. Nếu bạn không bận tâm kiểm tra nếu các chỉ số có thể vượt quá giới hạn thì nó sẽ nhanh hơn. Phải mất thời gian để thực hiện kiểm tra.

Tức là, nếu kiểm tra giới hạn là đúng, nó sẽ kiểm tra xem liệu chỉ mục nằm trong phạm vi của vectơ trước khi đọc hoặc ghi vào bộ nhớ. Và nếu không nó sẽ ném một lỗi. Nếu boundcheck là false, nó sẽ đọc hoặc ghi vào con trỏ ngay cả khi chỉ mục nằm ngoài giới hạn, đưa ra dữ liệu sai bằng cách đọc và ghi vào dữ liệu bộ nhớ bị hỏng bằng cách viết.

Từ tài liệu:

Các tra cứu mảng vẫn đang bị chậm lại bởi hai yếu tố:

1) Bounds kiểm tra được thực hiện.

2) Chỉ số âm được kiểm tra và xử lý chính xác.

Hậu quả của việc không ràng buộc kiểm tra phúc:

Bây giờ tiếp giáp kiểm tra không được thực hiện (và, như một tác dụng phụ, nếu bạn "làm '' xảy ra để truy cập ngoài giới hạn, bạn sẽ trong trường hợp tốt nhất làm hỏng chương trình của bạn và trong trường hợp xấu nhất là dữ liệu bị hỏng).

Trường hợp này đặc biệt quan trọng là bạn có thể không có véc tơ nào. Dưới đây là những cảnh báo từ các tài liệu:

Cảnh báo

Tốc độ đi kèm với một số chi phí. Đặc biệt, có thể nguy hiểm khi đặt các đối tượng được nhập (như f, g và h trong mã mẫu của chúng tôi) thành Không. Đặt các đối tượng đó thành Không là hoàn toàn hợp pháp, nhưng tất cả những gì bạn có thể làm với chúng là kiểm tra xem chúng có Không. Tất cả việc sử dụng khác (tra cứu thuộc tính hoặc lập chỉ mục) có thể phân tách hoặc làm hỏng dữ liệu (thay vì tăng các ngoại lệ như trong Python).

Quy tắc thực tế phức tạp hơn một chút nhưng thông báo chính là rõ ràng: Không sử dụng các đối tượng đã nhập mà không biết rằng chúng không được đặt thành Không.

http://docs.cython.org/src/userguide/numpy_tutorial.html

+2

Tôi nghĩ rằng lý do mà câu hỏi được đặt ra là trong trường hợp này 'boundscheck (True)' là nhanh hơn, đó là phản trực giác. – DavidW

+0

Ohh !!!!! Điểm tốt! Nó là để truy cập trực quan mà tôi thậm chí đọc câu hỏi sai! Tôi nghĩ câu hỏi đặt ngược lại. –

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