2009-04-20 19 views
12

Ho eseguito questa funzione in C utilizzando le chiamate di sistema (aperto, lettura e scrittura) per simulare la funzione "gatto" nei sistemi Linux ed è più lento di quello reale ...Perché la mia funzione "gatto" con le chiamate di sistema è più lenta rispetto al "gatto" di Linux?

Sto usando lo stesso dimensione del buffer come il vero "gatto" e usando "strace" penso che stia facendo la stessa quantità di chiamate di sistema. Ma l'uscita dal mio "gatto" è un po 'più lenta del vero "gatto".

Questo è il codice che ho:

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

che sto leggendo da un file (che mi passa come argomento di principale, credo che il codice non è necessario qui) che io chiamo il Catprint() funziona con quel descrittore di file e 1 per il descrittore di output, quindi stampa su stdout.

Non capisco perché è più lento perché sto usando lo stesso file per il test e con entrambi (il vero "gatto" e il mio) c'è solo un read() e uno write() per l'intero testo. Non dovrebbe l'intero testo apparire sullo schermo?

P.S: Ho taggato questo come compito a casa anche se la mia domanda qui (perché è più lenta) non fa parte dei compiti. Ho solo bisogno di usare le chiamate di sistema per creare una funzione di tipo "gatto", che è fatta. Sono solo incuriosito dal mio codice che è un po 'più lento.

problema risolto con la stupidità DA ME:
ho appena deciso di chiamare il gatto originale di Linux un paio di volte sullo stesso file, una dopo l'altra, e ho appena capito che era anche rallentare un po 'delle volte mi lo chiamò, lento come il mio. Immagino che tutto vada bene di ...

Scusa per aver sprecato il tuo tempo come questa gente.

+1

IMHO, il tag 'homework' è fuorviante. La tua domanda riguarda un fatto interessante. 'compiti a casa 'implicano il noioso lavoro dei principianti o (all'altra estremità della scala) una domanda a quiz. –

+0

BTW la gestione dell'errore (ad esempio scrittura di ritorno -1) non è corretta se l'errore si verifica nella seconda scrittura(). – jpalecek

+0

Puoi cancellare il tag dei compiti se pensi che sia meglio ... Cosa intendi con jpalecek? C'è solo una scrittura (come nella chiamata di sistema), ho solo una funzione ausiliaria. Se la funzione write() all'interno di quella funzione ausiliaria fallisce, ho bisogno di restituire il -1 fino al punto in cui è stato chiamato catPrint() ... –

risposta

15

Ah, in base alla modifica è stato morso dal buffer readahead. Non è possibile testare due programmi che leggono i file fianco a fianco eseguendoli una volta. Il primo è sempre più lento poiché il file è su disco, una volta che il file è in memoria, il secondo verrà eseguito più velocemente, è necessario creare nuovi dati per ognuno o eseguirne uno e quindi eseguire entrambi in modo che entrambi ottengano il vantaggio del buffer readahead.

1

Quanto? Il gatto canonico è qualcosa come

char bufr[BUFSIZ]; 
ssize_t len; 

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

che salva poche istruzioni.

+0

Questa potrebbe essere la versione canonica, ma errata (per esempio se il segnale arriva mentre scrivi()) – jpalecek

+0

Quale parte di "qualcosa come" ti è mancata? –

+0

Come ho detto, gatto originale e il mio gatto, entrambi chiamano uno read() con una dimensione del buffer di 32768 e un write() con la stessa dimensione del buffer e un'ultima lettura() alla fine (quando non legge nulla altro e termina). –

3

Forse hai compilato senza ottimizzazione (o senza un'impostazione di ottimizzazione così alta)?

Inoltre, il tuo codice chiamerà sysWriteBuffer una volta con readBytes uguale a zero - forse che (parzialmente) lo spiega?

Si potrebbe anche in linea sysWriteBuffer (tramite un commutatore o manualmente).

"inlining" significa copiare il corpo di una funzione nel proprio sito di chiamata per rimuovere il sovraccarico di chiamata di una funzione. A volte i compilatori lo fanno automaticamente (penso che -O3 abiliti questa ottimizzazione in gcc). È inoltre possibile utilizzare la parola chiave inline in gcc per indicare al compilatore di incorporare una funzione. Se si esegue questa operazione, la sua dichiarazione sarà simile a questa:

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

Se usi strace su cat vedrai che succede anche lì, quindi l'ho appena lasciato ... E sto usando il flag -O2. –

+0

Puoi provare "-O3 -funroll_loops" e vedere come funziona. Meglio ancora sarebbe determinare le bandiere esatte con cui è stato compilato il gatto. –

+0

Solo una nota, il lembo è -funroll-loop (il secondo trattino non è un trattino basso), e non penso che farà comunque molto in questo caso. – Anthony

1

Hai confrontare strace s di entrambi? Potresti provare a utilizzare il parametro -tt in modo da ottenere i tempi delle syscalls.

+0

Le mie conoscenze su strace non sono molte e ho provato il parametro -tt e il numero di numeri è apparso ma non riesco a capire il loro significato. –

+0

Prova a trovare la lettura e scrittura della parte (l'output dovrebbe avere il formato "time syscall (parametri) = valore restituito", quindi trova read() o write()) e postalo – jpalecek

3

Ricerca mmap (2).

Ti getteranno via le sottigliezze di ftell/fread, ma salterà uno strato di indirezione se la velocità di lettura è davvero importante.

+0

Grazie, ho avuto bisogno di quel mmap .. –

+0

Non sono autorizzato a utilizzare nient'altro per questo esercizio. –

2

Senza confrontare i codici sorgente, è difficile da dire. Se stai confrontando il tuo gatto con GNU cat, ricorda che stai confrontando un codice di poche ore/giorni con un codice che si è evoluto per più di venti anni.

Si consiglia di eseguire un'analisi delle prestazioni più completa, eseguendo entrambi i programmi con diverse dimensioni di input, da dispositivi diversi (un disco RAM sarebbe buono) e più volte di seguito. Devi provare a determinare DOVE nel tuo programma è più lento.

Dal momento che il gatto stesso è davvero banale (e in un commento hai già detto che stai già ottimizzando la compilazione), scommetto che l'impatto delle prestazioni che stai osservando non è nell'algoritmo vero e proprio, ma nei tempi di caricamento del programma. Se il binario di sistema è prelinked (che è comune nella maggior parte delle distro al giorno d'oggi), vedrai che è caricato più velocemente di qualsiasi programma tu compili (fino a includere la prelettura dei programmi).

Problemi correlati