Чому syslog настільки повільніше, ніж файл IO?


9

Я написав просту програму тестування для вимірювання продуктивності функції syslog. Це результати моєї тестової системи: (Debian 6.0.2 з Linux 2.6.32-5-amd64)

Тестовий виклик Дзвінки тривалості корисної навантаження 
                      [] [MB] [s] [MB / s]    
-------------------- ---------- ---------- ---------- ----------
syslog 200000 10,00 7,81 1,28      
syslog% s 200000 10,00 9,94 1,01      
написати / dev / null 200000 10,00 0,03 343,93    
printf% s 200000 10,00 0,13 76,29     

Тестова програма виконала 200000 системних дзвінків, записавши 50 байт даних під час кожного дзвінка.

Чому Syslog удесятеро повільніше, ніж IO файлів?

Це програма, яку я використовував для виконання тесту:

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

Імовірно, виклики системного журналу є складнішими, мають механізм "повідомлення та відповідь", мають більше накладних витрат, переміщаються між декількома процесами в просторі користувача (на відміну від запису на пристрій чи консоль) і не повертаються, поки повідомлення не буде успішно виконано прийнято.
afrazier

1
Відповідно до відповіді Річарда, чи виглядають цифри подібними, якщо після fprintf () ви додасте fflush (fp)?
sep332

@ sep3332 Після додавання O_SYNCпрапорця до open()функції та fflush(fp)після кожного fprintf()дзвінка результати стають [3.86, 3.63, 151.53, 23.00] MB/sна моєму комп’ютері (тестування Lenovo T61, Debian). Зараз це здається кращим, але, перевірте /etc/rsyslog.conf, він вже знаходиться в несинхронізованому режимі для системних журналів.
Xiè Jìléi

Відповіді:


11

Обидва виклики системного журналу видають по одній передачі () в сокет AF_UNIX за виклик. Навіть якщо syslogd відкидає дані, його все одно доведеться прочитати спочатку. На все це потрібен час.

Запис у / dev / null також видає одне записування () за виклик, але оскільки дані відкидаються, воно може дуже швидко оброблятися ядром.

Виклики fprintf () генерують лише одне записування () на кожні 4096 байтів, що передаються, тобто приблизно на кожні вісімдесят викликів printf. Кожен включає лише передачу даних з буфера libc в буфери ядра. Зв'язок з диском буде (порівняно принаймні) дуже повільною, але за відсутності явних синхронізаційних дзвінків може відбутися пізніше (можливо, навіть після завершення процесу).

Якщо коротко: syslog повільніше, ніж / dev / null, тому що він робить багато роботи і повільніше, ніж printf у файл через буферизацію.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.