2010-02-10 27 views
5

Tôi đã tự hỏi liệu đây có phải là hành vi được mong đợi trong C++ hay không. Đoạn code dưới đây chạy vào khoảng 0,001 ms:Viết chậm vào mảng trong C++

for(int l=0;l<100000;l++){ 
     int total=0; 
     for(int i = 0; i < num_elements; i++) 
     { 
      total+=i; 
     } 
    } 

Tuy nhiên nếu kết quả được ghi vào một mảng, thời gian thực hiện bắn lên đến 15 ms:

int *values=(int*)malloc(sizeof(int)*100000); 
     for(int l=0;l<100000;l++){ 
      int total=0; 
      for(unsigned int i = 0; i < num_elements; i++) 
      { 
       total+=i; 
      } 
      values[l]=total; 
     } 

tôi có thể hiểu rằng văn bản cho mảng mất thời gian nhưng là thời gian tỷ lệ?

Chúc mừng mọi người

+0

Câu hỏi của bạn cho biết C, nhưng thẻ của bạn nói C++. Đó là cái nào? –

+0

xin lỗi, đúng là C++ nhưng nếu các khai báo int được chuyển ra ngoài vòng lặp thì C – Ljdawson

+0

@Laurence - Không, mã của bạn hoàn toàn tiêu chuẩn trong C99 và hầu hết các trình biên dịch C89 sẽ chấp nhận cú pháp bạn sử dụng. –

Trả lời

11

Ví dụ đầu tiên có thể được triển khai chỉ sử dụng thanh ghi CPU. Chúng có thể được truy cập hàng tỷ lần mỗi giây. Ví dụ thứ hai sử dụng rất nhiều bộ nhớ mà nó chắc chắn tràn L1 và có thể cache L2 (tùy thuộc vào mô hình CPU). Điều đó sẽ chậm hơn. Tuy nhiên, 15 ms/100.000 viết đi ra đến 1,5 ns cho mỗi viết - 667 Mhz hiệu quả. Đó là không phải là chậm.

+1

+1 để chỉ ra các thanh ghi cpu. Trong trường hợp thứ hai, mã đang bước qua bộ nhớ, viết byte (kéo vào các trang của bộ nhớ, buộc bộ nhớ cache để tuôn ra, ... sau đó chỉ viết một giá trị duy nhất). Trong trường hợp trước đây, nó có thể dễ dàng được tinh khiết L1. Phản ứng này nên được nhiều hơn bình chọn. – anon

+0

câu trả lời hay, cảm ơn – Ljdawson

10

Dường như trình biên dịch tối ưu hóa vòng lặp hoàn toàn trong trường hợp đầu tiên.

Tổng hiệu lực của vòng lặp là một no-op, do đó trình biên dịch chỉ xóa nó.

+0

aha! Tôi nghĩ nhiều, có cách nào để vô hiệu hóa tối ưu hóa này cho điểm chuẩn hay không? – Ljdawson

+0

Phần lớn phụ thuộc vào trình biên dịch và IDE bạn đang sử dụng. Kiểm tra trang trợ giúp/man page để biết những gì bạn cần làm để tắt tối ưu hóa. –

+1

thử sử dụng tổng số sau vòng lặp; hoặc thêm -O0 nếu bạn đang sử dụng gcc. – tristan

1

Tôi nghi ngờ rằng những gì bạn thấy là ảnh hưởng của virtual memory và có thể phân trang. Cuộc gọi malloc sẽ phân bổ một bộ nhớ có kích thước phù hợp có thể được đại diện bởi một số trang ảo. Mỗi trang được liên kết vào bộ nhớ quá trình riêng biệt.

Bạn cũng có thể đo chi phí gọi số malloc tùy thuộc vào cách bạn định thời gian vòng lặp. Trong cả hai trường hợp, hiệu suất sẽ rất nhạy cảm với các tùy chọn tối ưu hóa trình biên dịch, tùy chọn luồng, phiên bản trình biên dịch, phiên bản thời gian chạy và mọi thứ khác. Bạn không thể giả định một cách an toàn rằng chi phí là tuyến tính với kích thước của phân bổ. Điều duy nhất bạn có thể làm là đo lường nó và tìm ra cách tối ưu hóa tốt nhất khi nó đã được chứng minh là một vấn đề.

3

Rất đơn giản. Trong trường hợp đầu tiên, bạn chỉ có 3 biến, có thể dễ dàng lưu trữ trong GPR (mục đích chung), nhưng không có nghĩa là chúng luôn ở đó, nhưng chúng có thể nằm trong bộ nhớ cache L1, có nghĩa là chúng có thể được truy cập rất nhanh.

Trong trường hợp thứ hai Bạn có hơn 100 nghìn biến và Bạn cần khoảng 400kB để lưu chúng. Đó là deffinitely đến nhiều cho đăng ký và bộ nhớ cache L1. Trong trường hợp tốt nhất nó có thể là trong bộ nhớ cache L2, nhưng có lẽ không phải tất cả chúng sẽ ở trong L2. Nếu một cái gì đó không phải là trong đăng ký, L1, L2 (Tôi giả định rằng bộ vi xử lý của bạn không có L3) có nghĩa là bạn cần phải tìm kiếm nó trong bộ nhớ RAM và phải mất muuuuuch nhiều thời gian hơn.

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