2009-04-20 95 views
12

我已經在C中使用系統調用(打開,讀取和寫入)來模擬Linux系統中的「cat」函數,並且它比真實的函數慢...與Linux的「貓」相比,爲什麼我的系統調用的「貓」功能比較慢?

我正在使用相同的緩衝區大小作爲真正的「貓」,並使用「strace」我認爲這是做相同數量的系統調用。但是我的「貓」的輸出比真正的「貓」慢了一點。

這是我的代碼:我從文件中讀取

#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; 
} 

(即我傳遞作爲參數主,我覺得這裏不需要代碼)比我所說的catPrint()函數與該文件描述符和1輸出描述符,所以它打印到標準輸出。

我不明白爲什麼它比較慢,因爲我使用相同的文件進行測試,並且兩者(真正的「貓」和我的)只有一個read()和一個write()作爲整個文本。整個文字是不是應該出現在屏幕上?

P.S:我已經把這個標記爲家庭作業,雖然我的問題在這裏(爲什麼它比較慢)不是作業的一部分。我只需要使用系統調用來創建一個「貓」類型的函數,完成。我只是對我的代碼感興趣,這有點慢。

問題愚蠢解決FROM ME:
我決定打電話給linux的原貓幾次在同一個文件,一前一後,我才意識到,這也減緩了一些時代的我叫它,就像我自己一樣慢。我想一切都很好...

對不起,浪費你的時間這樣的人。

+1

恕我直言,`家庭作業`標籤是誤導。你的問題涉及一個有趣的背景事實。 「家庭作業」意味着無論是繁瑣的初學者工作還是(在量表的另一端)一個測驗問題。 – 2009-04-20 18:44:37

+0

如果在第二次寫入()時發生錯誤,則錯誤(即,寫入返回-1)處理不正確。 – jpalecek 2009-04-20 18:50:43

+0

如果你認爲它更好,你可以刪除作業標籤...你是什麼意思jpalecek?只有一個寫(如在系統調用中)我只有一個輔助功能。如果該輔助函數中的write()失敗,我需要將-1一直返回到調用catPrint()的地方...... – 2009-04-20 19:00:33

回答

15

啊,根據你的編輯,你被readahead緩衝區咬住了。您無法通過運行一次來​​測試兩個並排讀取文件的程序。第一個文件在磁盤上總是比較慢,一旦文件在內存中,第二個將運行得更快,你必須爲每個文件創建新數據或者運行一個,然後運行它們,這樣它們都能從readahead緩衝區中獲益。

1

多少錢?規範的貓就像

char bufr[BUFSIZ]; 
ssize_t len; 

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

它保存了幾條指令。

3

也許你編譯沒有優化(或沒有一樣高的優化設置)?也許這(部分)解釋的那樣 -

此外,您的代碼將與readBytes等於零打電話sysWriteBuffer一次?

您也可以通過編譯器開關或手動內聯sysWriteBuffer。

"inlining"意味着將函數的主體複製到其調用站點,以消除調用函數的開銷。有時編譯器會自動執行此操作(我認爲-O3在gcc中啓用了此優化)。您還可以使用inline關鍵字gcc告訴編譯器內聯函數。如果你這樣做,你的聲明將如下所示:

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

你比較了strace這兩者嗎?您可以嘗試使用-tt參數,以便獲取系統調用的時間。

3

研究mmap(2)。

您將會丟掉ftell/fread的細微差別,但是如果讀取吞吐量非常重要,它將跳過一層間接尋址。

2

沒有比較源代碼,很難說。如果您將您的貓與GNU貓進行比較,請記住您正在比較幾個小時/天的代碼與進化了二十多年的代碼。

您可能想要進行更全面的性能分析,從不同的設備(RAM磁盤很好)和連續多次運行具有不同輸入大小的兩個程序。您必須嘗試確定您的程序中的哪個部分比較慢。由於cat本身並不重要(並且你在評論中表示你已經在優化編譯),所以我敢打賭,你所觀察到的性能影響並不在實際算法中,而是在程序加載時間上。如果系統二進制文件是prelinked(這在當今大多數發行版中很常見),您會看到它的加載速度比您自己編譯的任何程序都快(直到您將程序包括在內)。