fprintf && write

From
Andrey Melnikov (2:5030/1340.116)
To
Boris Rudakov ()
Date
2003-06-04T13:18:10Z
Area
CARBON.COPY
 * Forwarded from area 'RU.UNIX.PROG'
                               Hello Boris!


 04 Jun 03 10:57, Boris Rudakov wrote to Andrey Melnikov:
 AM>> Что-то у меня лыжи не едут совсем.

 BR> Я по специализации не юниксоид, поэтому изначально в тред не встревал. Но
 BR> у тебя в тексте есть несколько ляпов, на которые я хотел бы обратить
 BR> внимание вчисле прочего уже сказанного :)
    Ляпы я уже поправил. ;)

 BR> Часть замечаний совсем "общего плана", не касаемо заданного вопроса.

 AM>> Беру софтину, которая всю свою разумную жизнь работала так:

 AM>>   out = fdopen(out_fd, "w");
 AM>>   ....

 AM>>   fprintf(out, "%s", buffer);

 BR> Не вижу ни малейшего смысла в подобных конструкциях. Кишки xrintfxxx
 BR> заняты тем, что интерпретируют единственный "%s" и тупо перекачивают
 BR> buffer в out. Накладные расходы в этой и подобных конструкциях
 BR> несущественны, но... Зачем они когда можно и без них ?
    Я от них и избавлялся.

 BR> Я в таких случаях пишу данные непосредственно туду куда нужно,
 BR> избегая лишних переписываний во внутренних буфферах.

 BR> Чен'ть типа write(out, .....);

 AM>>   ....

 AM>> Выкидываю все эти fprintf() и заменяю на свою функцию:

 AM>> static char wr_buf[1024];

 BR> Для теста - прокатит, а вообще стоит избегать глобальных переменных. Я
 BR> нахожу что весь код нужно писать реентерабельным. Если нет ОСОБЫХ причин
 BR> делать иначе :) Я бы этот буфер увеличил раза в 4 и засунул внутрь функции
 BR> :)
    Дороже выйдет. Войти в процедуру, отрезать кусок стека. Выйти - подчистить. Код у меня не реентрабельный - задача того не требует.

 AM>> write_out (int fd, char *fmt, ...){
 [куча глюко-кода skipp]
 AM>>    return 0;
 AM>> }

 AM>> И скорость падает в 2 (два) с лишним раза. Где я тут неправ ?

 BR> Если рассудить логически, то:

 BR> 1. write - синхронный блокирующий вызов (или я не прав ?). Но, как бы то
 BR> ни было, ты скармливаешь ему весь буффер. Если бы он у тебя выводил не
 BR> весь буффер, а часть - ты бы давно уже заметил что твой код неправилен и
 BR> поправил бы приращение буфера и декремент длины. Значит - write у тебя
 BR> пишет все одним махом. Значит - глюк не в нем.
    Не в нем. Прверено экспереметально.

 BR> 2. Кроме write у тебя есть только один вызов API - select (в Виндах я бы
 BR> сказал "Вызов функции ядра", но думаю что и тут с select этот термин будет
 BR> точен). Морал - тормозит (сверх ожидаемого) он.
    Наверное - слово тормозит здесь не самое уместное. Я бы сказал - чаще делиться временем со всеми остальными задачами. Или я неправ ?

 BR> Моя теория такова (еще раз шаркну ножкой что я не юниксоид, но основные
 BR> принципы едины):

 BR> * Твой код делает два системных вызова.
    Да. Но без них - у меня два варианта:

1. Получить засыпание при вызове fprintf(...) где-то в ядре на write(..) на очень большое время, что увы неприемлимо.
2. Использовать alarm(time), write()/fprintf(), alarm(0); - я получу 3 системных вызова.

 BR> * Твой код выводит все за одну итерацию (иначе ты бы уже заметил ошибки в
 BR> нем).
    Я их в нем заметил. Но из фидо сложно заканселить уже ушедшее письмо :)

 BR> Итого - ты делаешь ровно один select и ровно один write.
    Да, именно так.

 BR> * "Меня терзают смутные сомнения" что fprintf же делает только один -
 BR> синхроный блокирующий write. И делает только один write (правда х.з. что
 BR> он делает при переполнении внутренних буфферов при форматировании строки -
 BR> может быть он делает серию write по мере их заполнения; однако, думаю что
 BR> в твоем случае ему там хватает одного write).
    Наверное - во внутренностях glibc можно сломать все ноги.

 BR> * Так же меня "терзают смутные сомнения" что select - дорогой вызов,
 BR> дороже write.

 BR> Таким образом, сдается мне что двукратное замедление вызвано тем, что ты в
 BR> два раза чаще беспокоишь ядро системы :)
    А вот такой вот я плохой - забочусь об состоянии endpoint'a...


     Andrey aka TEMHOTA-RIPN
--- GoldED+/LNX 1.1.4.7
 * Origin: Powered by SlackWare Linux (2:5030/1340.116)