2009-04-20 4 views
12

Я сделал эту функцию в C, используя системные вызовы (открытые, чтение и запись), чтобы имитировать функцию «cat» в системах Linux, и она медленнее, чем реальная ...Почему моя «кошка» с системными вызовами медленнее по сравнению с «кошкой» 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; 
} 

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

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

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

задача, решаемая с глупостью ОТ МЕНЯ:
Я просто решил назвать оригинальный кот в Linux несколько раз на тот же файл, один за другим, и я понял, что это также замедлять некоторые времена я называется так же медленно, как и моя. Я думаю, все в порядке, чем ...

Извините за то, что тратили свое время, как этот человек.

+1

IMHO, тег 'homework' вводит в заблуждение. Ваш вопрос касается интересного фона. «домашняя работа» подразумевает либо утомительную работу новичков, либо (на другом конце шкалы) вопрос викторины. –

+0

BTW ошибка ошибки (т. Е. Запись возвращаемого -1) неверна, если ошибка возникает во второй записи(). – jpalecek

+0

Вы можете удалить тег домашней работы, если считаете, что это лучше ... Что значит jpalecek? Есть только одна запись (как в системном вызове) У меня есть только вспомогательная функция. Если функция write() внутри этой вспомогательной функции терпит неудачу, мне нужно вернуть -1 до того момента, когда была вызвана catPrint() ... –

ответ

15

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

1

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

char bufr[BUFSIZ]; 
ssize_t len; 

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

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

+0

Это может быть каноническая версия, но некорректная (например, если сигнал приходит во время записи()) – jpalecek

+0

Какая часть «чего-то типа» вы пропустили? –

+0

Как я уже сказал, оригинальная кошка и моя кошка, оба называют один read() с размером буфера 32768 и write() с тем же размером буфера и последним read() в конце (когда он ничего не читает) else и завершается). –

3

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

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

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

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

static inline int sysWriteBuffer(int fdout, char *buffer, ssize_t readBytes) { 
.... 
+0

Если вы используете strace на cat, вы увидите, что это также происходит там, поэтому я просто оставил его ... И я использую флаг -O2. –

+0

Вы можете попробовать «-O3 -funroll_loops» и посмотреть, как это происходит. Еще лучше было бы определить точные флаги, с которыми была скомпилирована кошка. –

+0

Просто примечание: лоскут - это петли -funroll-loops (второй дефис не подчеркивается), и я не думаю, что в этом случае он будет делать много. – Anthony

1

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

+0

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

+0

Попытайтесь найти чтение и запись деталей (выход должен иметь формат «syscall (parameters) = возвращаемое значение», поэтому найдите read() или write()) и опубликуйте его – jpalecek

3

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

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

+0

Спасибо, мне понадобилось, что mmap .. –

+0

Мне не разрешено использовать что-либо еще для этого упражнения. –

2

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

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

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

Смежные вопросы