2009-04-20 13 views
12

Tôi đã thực hiện chức năng này trong C bằng cách sử dụng các cuộc gọi hệ thống (mở, đọc và ghi) để mô phỏng chức năng "mèo" trong hệ thống Linux và nó chậm hơn so với thực tế ...Tại sao chức năng "mèo" của tôi với các cuộc gọi hệ thống chậm hơn so với "con mèo" của Linux?

Tôi đang sử dụng cùng một kích thước bộ đệm là "con mèo" thực sự và sử dụng "strace" Tôi nghĩ rằng nó làm cho cùng một số lượng các cuộc gọi hệ thống. Nhưng đầu ra từ "con mèo" của tôi chậm hơn một chút so với "con mèo" thực sự.

Đây là mã tôi có:

#define BUFSIZ 32768 

int sysWriteBuffer(int fdout, char *buffer, ssize_t readBytes) { 
    ssize_t writtenBytes = 0; 

    while(writtenBytes < readBytes) { 
     writtenBytes += write(fdout, 
      buffer + writtenBytes, readBytes - writtenBytes); 
     if(writtenBytes == -1) { 
      return -1; 
     } 
    } 

    return 0; 
} 

int catPrint(int fdin, int fdout) { 
    char buffer[BUFSIZ]; 
    ssize_t readBytes; 

    do { 
     readBytes = read(fdin, buffer, BUFSIZ); 

     if(readBytes == -1) { 
      return -1; 
     } 

     if(sysWriteBuffer(fdout, buffer, readBytes) == -1) { 
      return -1; 
     } 
    } while(readBytes > 0); 

    return 0; 
} 

Tôi đang đọc từ một tập tin (mà tôi vượt qua như là đối số to main, tôi nghĩ rằng mã đó là không cần thiết ở đây) hơn tôi gọi là catPrint() chức năng với bộ mô tả tập tin đó và 1 cho bộ mô tả đầu ra để nó in ra stdout.

Tôi không hiểu tại sao nó chậm hơn vì tôi đang sử dụng cùng một tệp để thử nghiệm và với cả hai (con mèo thật "và của tôi) chỉ có một lần đọc() và một ghi() cho toàn bộ văn bản. Không phải toàn bộ văn bản chỉ xuất hiện trên màn hình sao?

P.S: Tôi đã gắn thẻ bài tập này làm bài tập ở nhà mặc dù câu hỏi của tôi ở đây (tại sao nó chậm hơn) không phải là một phần của bài tập về nhà. Tôi chỉ cần sử dụng các cuộc gọi hệ thống để tạo ra một loại "mèo" loại, được thực hiện. Tôi chỉ bị hấp dẫn bởi mã của tôi hơi chậm hơn một chút.

VẤN ĐỀ giải quyết với sự ngu dốt TỪ ME:
Tôi chỉ quyết định gọi con mèo gốc linux của một vài lần trên cùng một tập tin, một sau khi khác, và tôi chỉ nhận ra rằng nó cũng đã được làm chậm một số lần tôi gọi nó, cũng chậm như của tôi. Tôi đoán mọi thứ đều tốt đẹp hơn ...

Xin lỗi vì đã lãng phí thời gian của bạn như người này.

+1

IMHO, thẻ 'bài tập về nhà' gây hiểu lầm. Câu hỏi của bạn liên quan đến một thực tế cơ bản thú vị. 'bài tập về nhà 'ngụ ý công việc của người mới bắt đầu tẻ nhạt hoặc (ở đầu kia của thang điểm) là một câu hỏi đố vui. –

+0

BTW lỗi (tức là viết trở lại -1) xử lý là không chính xác nếu lỗi xảy ra trên ghi thứ hai(). – jpalecek

+0

Bạn có thể xóa thẻ bài tập về nhà nếu bạn nghĩ nó tốt hơn ... Ý bạn là gì jpalecek? Chỉ có một ghi (như trong cuộc gọi hệ thống) tôi chỉ có một chức năng phụ trợ. Nếu hàm write() bên trong hàm phụ không thành công, tôi cần trả về -1 tất cả các cách để catPrint() được gọi là ... –

Trả lời

15

Ah, dựa trên chỉnh sửa của bạn, bạn đang bị bộ đệm readahead cắn. Bạn không thể kiểm tra hai chương trình đọc tập tin cạnh nhau bằng cách chạy chúng một lần. Đầu tiên luôn chậm hơn vì tệp nằm trên đĩa, khi tệp ở trong bộ nhớ thứ hai sẽ chạy nhanh hơn, bạn phải tạo dữ liệu mới cho mỗi hoặc chạy một tệp rồi chạy cả hai để cả hai đều nhận được lợi ích của bộ đệm readahead.

1

Bao nhiêu? Con mèo chuẩn tắc là một cái gì đó giống như

char bufr[BUFSIZ]; 
ssize_t len; 

while((len=read(fdin, bufr, BUFSIZ)) >0) 
    write(fdout, bufr, len); 

tiết kiệm một vài hướng dẫn.

+0

Đây có thể là phiên bản kinh điển, nhưng phiên bản không chính xác (ví dụ: nếu tín hiệu xuất hiện khi bạn viết()) – jpalecek

+0

Bạn đã bỏ lỡ phần nào của "thứ gì đó" như thế? –

+0

Như tôi đã nói, mèo ban đầu và con mèo của tôi, cả hai đều gọi một read() với kích thước bộ đệm là 32768 và một write() với cùng kích thước bộ đệm và đọc cuối() ở cuối (khi nó không đọc bất cứ thứ gì và chấm dứt). –

3

Có lẽ bạn đã biên soạn mà không tối ưu hóa (hoặc không có cài đặt tối ưu hóa cao)?

Ngoài ra, mã của bạn sẽ gọi sysWriteBuffer một lần với readBytes bằng 0 - có thể (một phần) giải thích nó?

Bạn cũng có thể nội tuyến sysWriteBuffer (thông qua chuyển đổi trình biên dịch hoặc bằng tay).

"inlining" có nghĩa là sao chép nội dung của một hàm vào trang web cuộc gọi của nó để xóa phí gọi hàm. Đôi khi trình biên dịch tự động thực hiện điều này (tôi nghĩ -O3 cho phép tối ưu hóa này trong gcc). Bạn cũng có thể sử dụng từ khóa inline trong gcc để cho trình biên dịch biết nội tuyến một hàm. Nếu bạn làm như vậy, khai báo của bạn sẽ trông giống như sau:

static inline int sysWriteBuffer(int fdout, char *buffer, ssize_t readBytes) { 
.... 
+0

Nếu bạn sử dụng strace trên mèo bạn sẽ thấy rằng nó cũng xảy ra ở đó, vì vậy tôi chỉ còn lại nó ... Và tôi đang sử dụng cờ -O2. –

+0

Bạn có thể thử "-O3 -funroll_loops" và xem cách thực hiện. Tốt hơn là phải xác định những lá cờ chính xác mà con mèo đã được biên soạn. –

+0

Chỉ cần một lưu ý, các nắp là -funroll-loop (gạch nối thứ hai không phải là gạch dưới), và tôi không nghĩ rằng nó sẽ làm rất nhiều trong trường hợp này anyway. – Anthony

1

Bạn đã so sánh strace s của cả hai? Bạn có thể thử sử dụng tham số -tt để bạn có được thời gian của các syscalls.

+0

Kiến thức của tôi về strace không nhiều và tôi đã thử tham số -tt và số lượng các số xuất hiện nhưng tôi không thể hiểu ý nghĩa của chúng. –

+0

Hãy thử tìm phần đọc và viết (đầu ra phải có định dạng "thời gian syscall (tham số) = giá trị trả về", vì vậy hãy tìm read() hoặc write()) và đăng nó – jpalecek

3

Nghiên cứu mmap (2).

Bạn sẽ ném các đường nhỏ của ftell/fread, nhưng nó sẽ bỏ qua một lớp hướng dẫn nếu thông lượng đọc thực sự quan trọng.

+0

Cảm ơn, tôi đã cần mmap đó .. –

+0

Tôi không được phép sử dụng bất cứ điều gì khác cho bài tập này. –

2

Nếu không so sánh mã nguồn, rất khó để nói. Nếu bạn đang so sánh con mèo của bạn với con mèo GNU, hãy nhớ rằng bạn đang so sánh một mã số đó là một vài giờ/ngày tuổi với một mã đã phát triển trong hơn hai mươi năm.

Bạn có thể muốn thực hiện phân tích hiệu suất toàn diện hơn, chạy cả hai chương trình với kích thước đầu vào khác nhau, từ các thiết bị khác nhau (đĩa RAM sẽ tốt) và nhiều lần liên tiếp. Bạn phải cố gắng xác định WHERE trong chương trình của bạn chậm hơn.

Vì bản thân mèo thực sự tầm thường (và bạn đã nói trong một nhận xét rằng bạn đã tối ưu hóa quá trình biên dịch), tôi đặt cược tác động hiệu suất mà bạn đang quan sát không có trong thuật toán thực tế, nhưng vào thời gian tải chương trình. Nếu hệ thống nhị phân là prelinked (phổ biến trên hầu hết các bản phân phối hiện nay), bạn sẽ thấy rằng nó được tải nhanh hơn bất kỳ chương trình nào bạn tự biên dịch (cho đến khi bạn bao gồm các chương trình của bạn prelinking).

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