Perché syslog è molto più lento del file IO?


9

Ho scritto un semplice programma di test per misurare le prestazioni della funzione syslog. Questi sono i risultati del mio sistema di test: (Debian 6.0.2 con Linux 2.6.32-5-amd64)

Test Case Calls Payload Duration Thoughput 
                      [] [MB] [s] [MB / s]    
-------------------- ---------- ---------- ---------- ----------
syslog 200000 10.00 7.81 1.28      
syslog% s 200000 10,00 9,94 1,01      
write / dev / null 200000 10.00 0.03 343.93    
printf% s 200000 10,00 0,13 76,29     

Il programma di test ha eseguito 200000 chiamate di sistema scrivendo 50 byte di dati durante ogni chiamata.

Perché Syslog è dieci volte più lento del file IO?

Questo è il programma che ho usato per eseguire il test:

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>

const int  iter  = 200000;
const char msg[] = "123456789 123456789 123456789 123456789 123456789";

struct timeval t0;
struct timeval t1;

void start ()
{
    gettimeofday (&t0, (void*)0);
}

void stop ()
{
    gettimeofday (&t1, (void*)0);
}

void report (char *action)
{
    double dt = (double)t1.tv_sec - (double)t0.tv_sec +
        1e-6 * ((double)t1.tv_usec - (double)t0.tv_usec);
    double mb = 1e-6 * sizeof (msg) * iter;

    if (action == NULL)
        printf ("Test Case             Calls       Payload     Duration    Thoughput \n"
                "                      []          [MB]        [s]         [MB/s]    \n"
                "--------------------  ----------  ----------  ----------  ----------\n");
    else {
        if (strlen (action) > 20) action[20] = 0;
        printf ("%-20s  %-10d  %-10.2f  %-10.2f  %-10.2f\n",
                action, iter, mb, dt, mb / dt);
    }
}

void test_syslog ()
{
    int i;

    openlog ("test_syslog", LOG_PID | LOG_NDELAY, LOG_LOCAL0);
    start ();
    for (i = 0; i < iter; i++)
        syslog (LOG_DEBUG, msg);
    stop ();
    closelog ();
    report ("syslog");
}

void test_syslog_format ()
{
    int i;

    openlog ("test_syslog", LOG_PID | LOG_NDELAY, LOG_LOCAL0);
    start ();
    for (i = 0; i < iter; i++)
        syslog (LOG_DEBUG, "%s", msg);
    stop ();
    closelog ();
    report ("syslog %s");
}

void test_write_devnull ()
{
    int i, fd;

    fd = open ("/dev/null", O_WRONLY);
    start ();
    for (i = 0; i < iter; i++)
        write (fd, msg, sizeof(msg));
    stop ();
    close (fd);
    report ("write /dev/null");
}

void test_printf ()
{
    int i;
    FILE *fp;

    fp = fopen ("/tmp/test_printf", "w");
    start ();
    for (i = 0; i < iter; i++)
        fprintf (fp, "%s", msg);
    stop ();
    fclose (fp);
    report ("printf %s");
}

int main (int argc, char **argv)
{
    report (NULL);
    test_syslog ();
    test_syslog_format ();
    test_write_devnull ();
    test_printf ();
}

Presumibilmente, le chiamate syslog sono più complesse, con un meccanismo di "messaggio e risposta", hanno un overhead maggiore, viaggiano tra più processi di spazio utente (diversamente dalla scrittura su un dispositivo o sulla console) e non ritorneranno fino a quando il messaggio non sarà andato a buon fine accettato.
Afrazier

1
Secondo la risposta di Richard, i numeri sembrano simili se aggiungi fflush (fp) dopo fprintf ()?
sep332,

@ sep3332 Dopo aver aggiunto il O_SYNCflag alla open()funzione e fflush(fp)dopo ogni fprintf()chiamata, i risultati diventano [3.86, 3.63, 151.53, 23.00] MB/snel mio computer (Lenovo T61, test Debian). Sembra meglio ora ma, controlla /etc/rsyslog.conf, è già in modalità non sincronizzata per syslogs.
Xiè Jìléi,

Risposte:


11

Sia il syslog chiama sia un send () ad un socket AF_UNIX per chiamata. Anche se syslogd scarta i dati, dovrà comunque leggerli prima. Tutto ciò richiede tempo.

Le scritture su / dev / null generano anche una scrittura () per chiamata ma poiché i dati vengono scartati possono essere elaborati molto rapidamente dal kernel.

Le chiamate fprintf () generano solo una write () per ogni 4096 byte che vengono trasferiti, vale a dire circa una ogni ottanta chiamate printf. Ognuno comporta solo il trasferimento di dati dal buffer di libc ai buffer del kernel. Il commit sul disco sarà (almeno a confronto) molto lento, ma in assenza di qualsiasi esplicita sincronizzazione le chiamate possono avvenire in seguito (forse anche dopo il termine del processo).

In breve: syslog è più lento di / dev / null perché sta facendo molto lavoro e più lentamente di printf su un file a causa del buffering.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.