Почему моя функция "cat" с системными вызовами медленнее, чем "cat" в Linux? - PullRequest
12 голосов
/ 20 апреля 2009

Я сделал эту функцию в C, используя системные вызовы (открытие, чтение и запись) для имитации функции "cat" в системах Linux, и она медленнее, чем настоящая ...

Я использую тот же размер буфера, что и настоящий "кот", и использую "strace", я думаю, что он делает такое же количество системных вызовов. Но вывод моей "кошки" немного медленнее, чем настоящей "кошки".

Это код, который у меня есть:

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

Я читаю из файла (который я передаю в качестве аргумента main, я думаю, что здесь код не нужен), чем вызываю функцию catPrint () с этим файловым дескриптором и 1 для выходного дескриптора, поэтому он печатается стандартный вывод.

Я не понимаю, почему это медленнее, потому что я использую один и тот же файл для тестирования, и для обоих (настоящий "кот" и мой) есть только одна read () и одна write () для всего текста. Разве весь текст не должен появляться на экране?

П.С .: Я отметил это как домашнее задание, хотя мой вопрос здесь (почему он медленнее) не является частью домашнего задания. Мне нужно было использовать системные вызовы только для создания функции типа «кошка», что и делается. Я просто заинтригован моим кодом, который немного медленнее.

ПРОБЛЕМА, РЕШЕННАЯ ГЛУПОСТЬЮ ОТ МЕНЯ:
Я просто решил вызывать оригинальную кошку linux несколько раз для одного и того же файла, один за другим, и я просто понял, что в некоторых случаях я вызывал его медленно, так же медленно, как и мой. Я думаю, все хорошо, чем ...

Извините, что потратил ваше время, как эти люди.

Ответы [ 6 ]

15 голосов
/ 20 апреля 2009

Ах, исходя из ваших правок, вас укусил буфер чтения. Вы не можете протестировать две программы, которые читают файлы рядом, запустив их один раз. Первый всегда медленнее, так как файл находится на диске, как только файл находится в памяти, второй будет работать быстрее, вы должны либо создать новые данные для каждого, либо запустить один, а затем запустить оба, чтобы они оба получили преимущество буфера readahead.

3 голосов
/ 20 апреля 2009

Исследования mmap (2).

Вы будете отбрасывать тонкости ftell / fread, но он пропустит слой косвенности, если пропускная способность чтения действительно важна.

3 голосов
/ 20 апреля 2009

Возможно, вы скомпилировали без оптимизации (или без такой высокой настройки оптимизации)?

Кроме того, ваш код будет вызывать sysWriteBuffer один раз с readBytes равным нулю - может, это (частично) это объясняет?

Вы также можете встроить sysWriteBuffer (либо с помощью переключателя компилятора, либо вручную).

"inlining" означает копирование тела функции на сайт вызова для устранения накладных расходов на вызов функции. Иногда компиляторы делают это автоматически (я думаю, что -O3 включает эту оптимизацию в gcc). Вы также можете использовать ключевое слово inline в gcc , чтобы указать компилятору встроить функцию. Если вы сделаете это, ваша декларация будет выглядеть так:

static inline int sysWriteBuffer(int fdout, char *buffer, ssize_t readBytes) {
....
2 голосов
/ 20 апреля 2009

Без сравнения исходников сложно сказать. Если вы сравниваете свою кошку с GNU cat, помните, что вы сравниваете код, которому несколько часов / дней, с кодом, который развивался более двадцати лет.

Возможно, вы захотите провести более всесторонний анализ производительности, запустив обе программы с разными размерами ввода, с разных устройств (хорошо подойдет ОЗУ) и несколько раз подряд. Вы должны попытаться определить, ГДЕ в вашей программе медленнее.

Поскольку cat сама по себе тривиальна (и вы сказали в комментарии, что уже оптимизируете компиляцию), держу пари, что наблюдаемое вами влияние на производительность зависит не от фактического алгоритма, а от времени загрузки программы. Если бинарный файл системы предварительно связан (что в наши дни распространено в большинстве дистрибутивов), вы увидите, что он загружается быстрее, чем любая программа, которую вы сами компилируете (пока вы не включите свои программы с предварительными ссылками).

1 голос
/ 20 апреля 2009

Вы сравнивали strace с обоих? Вы можете попытаться использовать параметр -tt, чтобы получить время системных вызовов.

1 голос
/ 20 апреля 2009

Сколько? Канонический кот - это что-то вроде

char bufr[BUFSIZ];
ssize_t len;

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

, который сохраняет несколько инструкций.

...