¿Por qué syslog es mucho más lento que el archivo IO?

9

Escribí un programa de prueba simple para medir el rendimiento de la función syslog. Estos son los resultados de mi sistema de prueba: (Debian 6.0.2 con Linux 2.6.32-5-amd64)

Caso de prueba Llamadas Duración de la carga útil Pensamiento 
                      [] [MB] [s] [MB / s]    
-------------------- ---------- ---------- ---------- ----------
syslog 200000 10.00 7.81 1.28      
syslog% s 200000 10.00 9.94 1.01      
escribir / dev / nulo 200000 10.00 0.03 343.93    
printf% s 200000 10.00 0.13 76.29     

El programa de prueba realizó 200000 llamadas al sistema escribiendo 50 bytes de datos durante cada llamada.

¿Por qué Syslog es más de diez veces más lento que el archivo IO?

Este es el programa que utilicé para realizar la prueba:

#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
fuente
Presumiblemente, las llamadas de syslog son más complejas, con un mecanismo de "mensaje y respuesta", tienen más sobrecarga, viajan entre múltiples procesos de espacio de usuario (a diferencia de escribir en un dispositivo o la consola) y no volverán hasta que el mensaje haya sido exitoso aceptado.
Afrazier 01 de
1
Según la respuesta de Richard, ¿los números se ven similares si agrega fflush (fp) después de fprintf ()?
sep332
@ sep3332 Después de agregar un O_SYNCindicador a la open()función y fflush(fp)después de cada fprintf()llamada, los resultados se convierten [3.86, 3.63, 151.53, 23.00] MB/sen mi computadora (Lenovo T61, prueba de Debian). Parece mejor ahora pero, compruebe /etc/rsyslog.conf, ya está en modo no sincronizado para syslogs.
Xiè Jìléi

Respuestas:

11

Las llamadas de syslog emiten un envío () a un socket AF_UNIX por llamada. Incluso si el syslogd descarta los datos, todavía tendrá que leerlos primero. Todo esto lleva tiempo.

Las escrituras en / dev / null también emiten una escritura () por llamada, pero como los datos se descartan, el núcleo puede procesarlos muy rápidamente.

Las llamadas fprintf () solo generan una escritura () por cada 4096 bytes que se transfieren, es decir, aproximadamente una cada ochenta llamadas printf. Cada uno solo implica transferir datos desde el búfer de libc a los búferes del núcleo. La confirmación en el disco será (al menos en comparación) muy lenta, pero en ausencia de cualquier llamada de sincronización explícita puede ocurrir más tarde (tal vez incluso después de que finalice el proceso).

En resumen: syslog es más lento que / dev / null porque está haciendo mucho trabajo y más lento que printf en un archivo debido al almacenamiento en búfer.

Richard Kettlewell
fuente