Warum ist Syslog so viel langsamer als Datei-E / A?

9

Ich habe ein einfaches Testprogramm geschrieben, um die Leistung der Syslog-Funktion zu messen. Dies sind die Ergebnisse meines Testsystems: (Debian 6.0.2 mit Linux 2.6.32-5-amd64)

Testfall ruft Payload Duration Thoughput auf 
                      [] [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     

Das Testprogramm hat 200000 Systemaufrufe ausgeführt und bei jedem Aufruf 50 Datenbytes geschrieben.

Warum ist Syslog mehr als zehnmal langsamer als Datei-E / A?

Dies ist das Programm, mit dem ich den Test durchgeführt habe:

#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 ();
}
ceving
quelle
Vermutlich sind Syslog-Aufrufe komplexer, mit einem "Message & Response" -Mechanismus, haben mehr Overhead, wechseln zwischen mehreren User-Space-Prozessen (im Gegensatz zum Schreiben auf ein Gerät oder die Konsole) und kehren erst zurück, wenn die Nachricht erfolgreich war akzeptiert.
Afrazier
1
Sehen die Zahlen laut Richards Antwort ähnlich aus, wenn Sie fflush (fp) nach fprintf () hinzufügen?
Sep332
@ sep3332 Nach dem Hinzufügen eines O_SYNCFlags zur open()Funktion und fflush(fp)nach jedem Aufruf werden fprintf()die Ergebnisse [3.86, 3.63, 151.53, 23.00] MB/sauf meinem Computer gespeichert (Lenovo T61, Debian-Test). Es scheint jetzt besser zu sein, aber überprüfen Sie /etc/rsyslog.conf, dass es für Syslogs bereits nicht synchron ist.
Xiè Jìléi

Antworten:

11

Die Syslog-Aufrufe geben beide pro Aufruf ein send () an einen AF_UNIX-Socket aus. Selbst wenn das syslogd die Daten verwirft, muss es sie zuerst lesen. Das alles braucht Zeit.

Die Schreibvorgänge in / dev / null geben ebenfalls ein write () pro Aufruf aus. Da die Daten jedoch verworfen werden, können sie vom Kernel sehr schnell verarbeitet werden.

Die Aufrufe von fprintf () erzeugen nur ein Schreiben () für jeweils 4096 übertragene Bytes, dh etwa eines von achtzig printf-Aufrufen. In jedem Fall werden nur Daten aus dem libc-Puffer in die Puffer des Kernels übertragen. Das Festschreiben auf die Festplatte ist (zumindest im Vergleich) sehr langsam, aber wenn keine expliziten Synchronisationsaufrufe vorliegen, kann dies später erfolgen (möglicherweise sogar nach Beendigung des Prozesses).

Kurz gesagt: syslog ist langsamer als / dev / null, weil es viel Arbeit leistet und aufgrund der Pufferung langsamer als printf in eine Datei.

Richard Kettlewell
quelle