2010-07-08 29 views
6

Chương trình của tôi đọc hàng tá tệp rất lớn song song, chỉ một dòng tại một thời điểm. Dường như nút cổ chai hiệu suất chính là HDD tìm thời gian từ tập tin vào tập tin (mặc dù tôi không hoàn toàn chắc chắn làm thế nào để xác minh điều này), vì vậy tôi nghĩ rằng nó sẽ nhanh hơn nếu tôi có thể đệm đầu vào.Làm thế nào để thay đổi kích thước bộ đệm với tăng :: iostreams?

Tôi đang sử dụng C++ như thế này để đọc các tập tin của mình thông qua tăng :: iostreams "lọc suối":

input = new filtering_istream; 
input->push(gzip_decompressor()); 
file_source in (fname); 
input->push(in); 

Theo documentation, file_source không có cách nào để thiết lập kích thước bộ đệm nhưng filtering_stream :: đẩy dường như:

void push(const T& t, 
    std::streamsize buffer_size, 
    std::streamsize pback_size); 

Vì vậy, tôi đã cố gắng input->push(in, 1E9) và thực sự sử dụng bộ nhớ chương trình của tôi bắn lên, nhưng tốc độ không thay đổi chút nào.

Tôi đã sai khi đọc đệm sẽ cải thiện hiệu suất? Hay tôi đã làm điều này sai? Tôi có thể đệm trực tiếp một file_source hay tôi cần tạo một filter_streambuf? Nếu sau này, nó hoạt động như thế nào? Tài liệu không chính xác đầy đủ các ví dụ.

Trả lời

2

Bạn cũng nên xem tiểu sử cũng thấy nút cổ chai ở đâu.

Có lẽ nó nằm trong hạt nhân, có thể là do giới hạn phần cứng của bạn. Cho đến khi bạn hồ sơ nó để tìm ra bạn đang stumbling trong bóng tối.

EDIT:

Ok, một câu trả lời thấu đáo hơn thời gian này, sau đó. Theo tài liệu Boost.Iostreams basic_file_source chỉ là một trình bao bọc xung quanh std::filebuf, lần lượt được xây dựng trên std::streambuf. Để trích dẫn tài liệu:

CopyConstructible and Assignable wrapper cho tiêu chuẩn :: basic_filebuf mở ở chế độ chỉ đọc.

streambuf không cung cấp một phương pháp pubsetbuf (không phải là tài liệu tham khảo tốt nhất có lẽ, nhưng google đầu tiên bật lên) mà bạn có thể, rõ ràng, sử dụng để kiểm soát kích thước bộ đệm.

Ví dụ:

#include <fstream> 

int main() 
{ 
    char buf[4096]; 
    std::ifstream f; 
    f.rdbuf()->pubsetbuf(buf, 4096); 
    f.open("/tmp/large_file", std::ios::binary); 

    while(!f.eof()) 
    { 
     char rbuf[1024]; 
     f.read(rbuf, 1024); 
    } 

    return 0; 
} 

Trong thử nghiệm của tôi (tối ưu hóa off, mặc dù) tôi thực sự có hiệu suất tồi tệ hơn với một bộ đệm 4096 byte hơn 16 byte đệm nhưng YMMV - một ví dụ tốt về lý do tại sao bạn nên luôn luôn hồ sơ đầu tiên :)

Nhưng, như bạn nói, các basic_file_sink không cung cấp bất kỳ phương tiện để truy cập này vì nó ẩn các filebuf cơ bản trong private part của nó.

Nếu bạn nghĩ rằng điều này là sai bạn có thể:

  1. Đôn đốc các nhà phát triển Boost để lộ chức năng như vậy, sử dụng danh sách gửi thư hoặc trac.
  2. Tự tạo filebuf trình bao bọc của bạn để lộ kích thước bộ đệm. Có một số section trong hướng dẫn giải thích cách viết các nguồn tùy chỉnh có thể là điểm khởi đầu tốt.
  3. Viết nguồn tùy chỉnh dựa trên mọi thứ, điều đó thực hiện tất cả bộ nhớ đệm bạn ưa thích.

Hãy nhớ rằng ổ cứng của bạn cũng như hạt nhân đã lưu vào bộ nhớ đệm và lưu vào bộ đọc tệp, tôi không nghĩ rằng bạn sẽ tăng hiệu suất từ ​​bộ nhớ đệm nhiều hơn.

Và kết thúc, một từ về lược tả. Có rất nhiều công cụ định hình mạnh mẽ có sẵn cho Linux, tôi thậm chí không biết một nửa tên của chúng, nhưng ví dụ có iotop là loại gọn gàng vì nó rất dễ sử dụng. Nó khá giống với hàng đầu nhưng thay vào đó chỉ ra các số liệu liên quan đến đĩa. Ví dụ:

Total DISK READ: 31.23 M/s | Total DISK WRITE: 109.36 K/s 
TID PRIO USER  DISK READ DISK WRITE SWAPIN  IO> COMMAND   
19502 be/4 staffan 31.23 M/s 0.00 B/s 0.00 % 91.93 % ./apa 

cho tôi biết rằng progam của tôi dành hơn 90% thời gian chờ IO, tức là IO bị ràng buộc. Nếu bạn cần thứ gì đó mạnh mẽ hơn, tôi chắc chắn rằng google có thể giúp bạn.

Và hãy nhớ rằng điểm chuẩn trên bộ nhớ cache nóng hoặc lạnh ảnh hưởng rất lớn đến kết quả.

+0

Có thể đây là câu hỏi cho một bài đăng khác, nhưng làm cách nào để tôi đăng tiểu sử? Tôi biết làm thế nào để sử dụng gprof, nhưng nó chỉ cho tôi biết về thời gian CPU, và ở đây tôi khá chắc chắn nút cổ chai là đĩa I/O. Hoặc nếu ai đó có thể cho tôi biết cách đặt kích thước bộ đệm chính xác, tôi có thể thử và xem nó có giúp ích không. – user387250

+0

@jwfoley: Tôi thích [Valgrind's] (http://valgrind.org/) callgrind profiler. Theo như kinh nghiệm của tôi đi (đọc như: Tôi không thể đảm bảo bất cứ điều gì) nó báo cáo thời gian dành cho các cuộc gọi hạt nhân là tốt, một cái gì đó tôi không bao giờ có thể nhận được gprof để làm. Tôi sử dụng nó để cấu hình một ứng dụng với OpenGL ví dụ, và nó báo cáo chính xác thời gian dành cho mã trình điều khiển video. Nó rất dễ sử dụng (valgrind --tool = callgrind ./your-app). Sử dụng [KCachegrind] (http://kcachegrind.sourceforge.net/html/Home.html) để diễn giải kết quả. Điểm duy nhất là ứng dụng của bạn sẽ chạy chậm hơn 20 lần trong khi định hình. – Staffan

+0

@Staffan: Được rồi, tôi đã thử callgrind + KCachegrind và tôi rất ấn tượng với hồ sơ, nhưng tôi vẫn không biết mình đang tìm gì. Kết quả trông khá giống với kết quả của gprof. Một cái gì đó gọi là T.3577 có một "Incl" cao. nhưng thấp "Tự"; hầu hết thời gian của nó dường như được chi tiêu trong std :: basic_ios. Có lẽ đó là đĩa I/O? Tôi vẫn muốn có câu trả lời cho câu hỏi ban đầu về cách đặt kích thước bộ đệm. Nếu nó dễ dàng, thì tôi có thể thử nó và xem nó có giúp ích gì không, nhưng dù sao thì cũng có ích. – user387250

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