Oberon space

General Category => Общий раздел => Тема начата: ilovb от Январь 16, 2013, 09:35:05 am

Название: Буферизация ввода/вывода
Отправлено: ilovb от Январь 16, 2013, 09:35:05 am
Обсуждение началось здесь: http://forum.oberoncore.ru/viewtopic.php?f=23&t=4214#p77131

Вопрос первый: Есть ли смысл заниматься оптимизацией буферизации I/O на современных жестких дисках в современных осях?
Вопрос второй: Почему в BB буфер имеет фиксированный размер 2 * 1024? Есть ли смысл в другом размере?
Вопрос третий: Есть ли смысл делать буфер под размер кластера? (если нет системного буфера)
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 16, 2013, 09:50:35 am
Обсуждение началось здесь: http://forum.oberoncore.ru/viewtopic.php?f=23&t=4214#p77131

Вопрос первый: Есть ли смысл заниматься оптимизацией буферизации I/O на современных жестких дисках в современных осях?
Имеет, но только в крайне специфических случаях (например в случае если ты пишешь собственную высоконагруженную СУБД). Скажем в MySQL в случае движка MyISAM все кеширование отдано на откуп ОСи, в случае innodb - кеширование свое. То есть, видимо, когда твой кеш сможет работать эффективней просто потому, что ты точно знаешь паттерн типичных запросов к диску в твоем приложении (а кэш общего назначения естественно заточен под усредненный вероятностный паттерн).

В современных ОСях по умолчанию ВСЯ не используемая приложениями память (а в случае видны - еще больше) уходит автоматом под дисковый кэш.

Ну и не забываем что у винтов еще свой личноперсональный кэш имеется.

Вопрос второй: Почему в BB буфер имеет фиксированный размер 2 * 1024? Есть ли смысл в другом размере?
Вроде же в исходном топике сказали, что сложилось исторически.

Вопрос третий: Есть ли смысл делать буфер под размер кластера? (если нет системного буфера)
Чтобы избавиться от системного буфера нужно очень специально постараться.

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

Впрочем, зачем рассуждать, если можно просто проверить? Поставь эксперимент и не парься. :-)
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 16, 2013, 10:28:49 am
Вопрос второй: Почему в BB буфер имеет фиксированный размер 2 * 1024? Есть ли смысл в другом размере?

В пакете bufio, обеспечивающем в Go буферизированный ввод/вывод дефолтный размер буфера - 4096 байт. Я полагаю это связано не с размером какого-то там кластера на диске, а с размером страницы памяти (4 Кб - пожалуй наиболее частовстречающийся размер страницы). В случае буфера важно обеспечить эффективность распределения и доступа к памяти.

http://golang.org/pkg/bufio/
http://golang.org/src/pkg/bufio/bufio.go
Название: Re: Буферизация ввода/вывода
Отправлено: pygubanov от Январь 16, 2013, 12:17:21 pm
по моему, когда скорость ввода кванта данных и скорость вывода кванта данных не равны, то буфер необходим для эффективной работы. Размер же буфера должен определятся конкретной реализацией.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 16, 2013, 12:32:34 pm
по моему, когда скорость ввода кванта данных и скорость вывода кванта данных не равны, то буфер необходим для эффективной работы. Размер же буфера должен определятся конкретной реализацией.
Так точно!
И важно понимать, что в данном случае диск совершенно вторичен. Буферизацию собственную делают лишь затем, чтобы поменьше системных вызовов было, а значит и переключений контекста. Системный вызов же какого-нибудь write обычно всего лишь перекладывает данные из нашего буфера в системный.

То есть fflush - это как раз оно, перекладывание данных из памяти приложения в систему.
А вот fsync уже вынудит систему все что есть в буфере положить на диск.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 16, 2013, 01:24:34 pm
по моему, когда скорость ввода кванта данных и скорость вывода кванта данных не равны, то буфер необходим для эффективной работы. Размер же буфера должен определятся конкретной реализацией.
Так точно!
И важно понимать, что в данном случае диск совершенно вторичен. Буферизацию собственную делают лишь затем, чтобы поменьше системных вызовов было, а значит и переключений контекста. Системный вызов же какого-нибудь write обычно всего лишь перекладывает данные из нашего буфера в системный.

То есть fflush - это как раз оно, перекладывание данных из памяти приложения в систему.
А вот fsync уже вынудит систему все что есть в буфере положить на диск.

Да, и понятно тогда почему размер буфера делается кратным размеру страницы памяти а не кластеру диска - ведь нам нужно быстро скопировать шмат памяти отсюда туда, а постранично это будет быстрее всего.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 16, 2013, 01:49:45 pm
По поводу 4096 вот тут написано:
http://msdn.microsoft.com/ru-ru/library/windows/desktop/cc644950(v=vs.85).aspx
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 16, 2013, 01:51:25 pm
Цитировать
Because buffer addresses for read and write operations must be sector-aligned, the application must have direct control of how these buffers are allocated. One way to sector-align buffers is to use the VirtualAlloc function to allocate the buffers.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 16, 2013, 06:58:57 pm
Код: (stdio.h) [Выделить]
...
/* Buffered I/O macros */

#define BUFSIZ  512

#ifndef _INTERNAL_IFSTRIP_
/*
 * Real default size for stdio buffers
 */
#define _INTERNAL_BUFSIZ    4096
#define _SMALL_BUFSIZ       512
#endif  /* _INTERNAL_IFSTRIP_ */
...
:D
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 16, 2013, 10:41:25 pm
По поводу 4096 вот тут написано:
http://msdn.microsoft.com/ru-ru/library/windows/desktop/cc644950(v=vs.85).aspx
Это не тот случай. В bufio никто не полагается на то, что системное кеширование будет отключено.  Также никто не затачивается под винду. Отключение системного дискового кеша это крайне экстремальный случай.

Вопрос - в ББ FILE_FLAG_NO_BUFFERING используется?

Ну и еще раз - буферизация (собственная, на стороне приложения) имеет смысл даже если файл с которым работаем лежит на disk on ram - виртуальном диске в ОЗУ. Потому что сильная экономия на переключении контекстов. Помнишь тормоза в c++ коде в той задачке? Это было ровно из за этого - при чтение и запись было, грубо говоря, не буферизированном. Постоянные системные вызовы. Заметь, что там мой код на c++ ВООБЩЕ с файлами на диске не работал.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 05:47:05 am
Это не тот случай. В bufio никто не полагается на то, что системное кеширование будет отключено.  Также никто не затачивается под винду. Отключение системного дискового кеша это крайне экстремальный случай.

Вопрос - в ББ FILE_FLAG_NO_BUFFERING используется?
Дисковый кэш никто не отключает. FILE_FLAG_NO_BUFFERING - отключает системный буфер и кэш windows (это позволяет читать/писать асинхронно). В ББ этот флаг не используется.
А вот в MS SQL используется:
Профессиональное руководство по Microsoft SQL Server: структура и реализация (http://books.google.ru/books?id=kuBCF2bsW7YC&pg=PA268&dq=FILE_FLAG_NO_BUFFERING&hl=ru&sa=X&ei=hY33UNW4AciG4gTVpYC4Aw&ved=0CDQQ6AEwAA#v=onepage&q=FILE_FLAG_NO_BUFFERING&f=false)

Ничего страшного в отключении системного буфера нет. На Turbo Pascal ведь пользовались блочным вводом/выводом и никто не боялся :)

Ну и еще раз - буферизация (собственная, на стороне приложения) имеет смысл даже если файл с которым работаем лежит на disk on ram - виртуальном диске в ОЗУ. Потому что сильная экономия на переключении контекстов. Помнишь тормоза в c++ коде в той задачке? Это было ровно из за этого - при чтение и запись было, грубо говоря, не буферизированном. Постоянные системные вызовы. Заметь, что там мой код на c++ ВООБЩЕ с файлами на диске не работал.
А я и не спорю с этим  :)
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 05:54:18 am
Это не тот случай. В bufio никто не полагается на то, что системное кеширование будет отключено.  Также никто не затачивается под винду. Отключение системного дискового кеша это крайне экстремальный случай.

Вопрос - в ББ FILE_FLAG_NO_BUFFERING используется?
Дисковый кэш никто не отключает. FILE_FLAG_NO_BUFFERING - отключает системный буфер и кэш windows (это позволяет читать/писать асинхронно). В ББ этот флаг не используется.
А вот в MS SQL используется:
Профессиональное руководство по Microsoft SQL Server: структура и реализация (http://books.google.ru/books?id=kuBCF2bsW7YC&pg=PA268&dq=FILE_FLAG_NO_BUFFERING&hl=ru&sa=X&ei=hY33UNW4AciG4gTVpYC4Aw&ved=0CDQQ6AEwAA#v=onepage&q=FILE_FLAG_NO_BUFFERING&f=false)

Ничего страшного в отключении системного буфера нет. На Turbo Pascal ведь пользовались блочным вводом/выводом и никто не боялся :)
Я именно про системный дисковый кеш и говорил (я не говорил про кеш самого hdd).
Так вот, отключать его в 99.9% случаев смысла не имеет. Имеет смысл отключать только в о-очень редких случаях (см мой первый пост про MySQL). ББ - это не тот случай когда нужно его отключать.

Какую бы аналогию привести... Ну, вот например: пишешь ты на java, или там на c# каком-нибудь. И берешь, лезешь в рантайм и отключаешь автоматическое включение сборщика мусора, вместо этого сам начинаешь дергать GC тогда когда считаешь что пора уже собирать мусор. Или даже пишешь свой сборщик мусора, и заменяешь им штатный.

На всякий случай еще раз - буферизированный ввод-вывод используется в той же стандартной сишной либе не из за того, что это медленный диск на той стороне, а из за того, что это syscall'ы, число их и минимизируем. Ибо переключение контекстов, а это дорого.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 05:57:26 am
Вот новость в тему: http://www.opennet.ru/opennews/art.shtml?num=35849

Так что с системным кешированием соревноваться смысла нет (и тем более его отключать). Точнее есть смысл в 0.01% задач.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 06:32:50 am
На всякий случай еще раз - буферизированный ввод-вывод используется в той же стандартной сишной либе не из за того, что это медленный диск на той стороне, а из за того, что это syscall'ы, число их и минимизируем. Ибо переключение контекстов, а это дорого.
А если ты на Си под DOS пишешь?  :)
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 06:37:40 am
На всякий случай еще раз - буферизированный ввод-вывод используется в той же стандартной сишной либе не из за того, что это медленный диск на той стороне, а из за того, что это syscall'ы, число их и минимизируем. Ибо переключение контекстов, а это дорого.
А если ты на Си под DOS пишешь?  :)
Так там тоже вроде как через int 21h это делается. Нет? То есть через прерывание - а это медленно. Это рраз.

Два - системный буфер в ДОС-е тоже есть (как бишь эту системную стандартную утиль звали, которая его включает... не помню, надо же... А! Во! smartdrv)
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 06:38:26 am
Но я в принципе согласен что в современных осях производительности системного кэширования достаточно для большинства задач. Свой буфер имеет смысл делать только в экстремальных задачах.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 06:47:03 am
Так там тоже вроде как через int 21h это делается. Нет? То есть через прерывание - а это медленно. Это рраз.
Два - системный буфер в ДОС-е тоже есть (как бишь эту системную стандартную утиль звали, которая его включает... не помню, надо же... А! Во! smartdrv)
Не шарю в тонкостях IO DOS. Но в TP вроде был свой буфер, и читалось/писалось из него прямо на диск (а не в какой-то системный буфер). И потому в TP блочный ввод вывод с буфером кратным размеру сектора давал ускорение на порядки за счет минимизации числа обращений к диску. То же самое в оригинальном Обероне.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 06:52:07 am
Кроме того если ты не контролируешь буфер, то скорее всего будут проблемы при реализации транзакций например, ибо неизвестно на диске уже данные или нет.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 07:22:06 am
Так там тоже вроде как через int 21h это делается. Нет? То есть через прерывание - а это медленно. Это рраз.
Два - системный буфер в ДОС-е тоже есть (как бишь эту системную стандартную утиль звали, которая его включает... не помню, надо же... А! Во! smartdrv)
Не шарю в тонкостях IO DOS. Но в TP вроде был свой буфер, и читалось/писалось из него прямо на диск (а не в какой-то системный буфер). И потому в TP блочный ввод вывод с буфером кратным размеру сектора давал ускорение на порядки за счет минимизации числа обращений к диску. То же самое в оригинальном Обероне.
А вот если запустить до того smartdrv, то разница будет уже не столь велика :-) То есть экономия будет просто за счет меньшего числа прерываний.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 10:45:43 am
Ради интереса посмотрел размеры буферов в разных Оберонах:
1. А2 - 4 КБ
2. ETH Oberon - 4 КБ
3. Linz Oberon V4 - 1 КБ
4. оригинальный Oberon:
BufferRecord =
RECORD apos, lim: INTEGER;
   mod: BOOLEAN;
   next: Buffer;
   data: FileDir.DataSector;
END

где:
DataSector = RECORD(Kernel.Sector)
    B: ARRAY SectorSize OF SYSTEM.BYTE;
END

где:
SectorSize = 1024
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 10:49:47 am
Охохо. По моему, у нас тут идет смешение теплого с мягким.

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

Если мы пишем прикладное ПО, работающее на ОС у которой есть свой буфер, то критерии выбора размера буфера будут уже совсем другие. Ибо это буфер взаимодействия с ОС, а не буфер взаимодействия с блочным устройством.

Внимание вопрос - какой случай нас интересует?
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:02:06 am
Тык вот именно! Я это и пытаюсь понять. Во всех приведенных системах размер буфера выбран конкретного размера по объективным причинам, ибо все эти системы могут работать нативно. И там это дает существенный профит.

А вот почему буфер ББ такой непонятно. И непонятно почему он фиксированный. Кроме того буфер ББ - это не то же самое, что буфер Оберона, т.к. нет прямого обмена с файловой системой. Т.е. в ББ буфер пользовательский и его размер по идее не зависит от файловой системы. Системный буфер windows делает за ББ ту работу, которая лежала на буфере оригинального Оберона.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:05:05 am
И кроме того, valexey, управление файлами и буферами во всех Оберонах одинаковое. В этом то и странность.

ps А системный буфер windows вообще 256КБ...
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 11:16:45 am
И кроме того, valexey, управление файлами и буферами во всех Оберонах одинаковое. В этом то и странность.

ps А системный буфер windows вообще 256КБ...

Да ладно? А это что такое?
(http://cdn.imghack.se/images/142d19b8289f5ea243584e21417e4502.png)
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:20:50 am
Это весь кэш. А я говорю про отдельный буфер:
Цитировать
As depicted by the solid arrows in the previous figure, a 256 KB region of data is read into a 256 KB cache "slot" in system address space when it is first requested by the cache manager during a file read operation. A user-mode process then copies the data in this slot to its own address space. When the process has completed its data access, it writes the altered data back to the same slot in the system cache, as shown by the dotted arrow between the process address space and the system cache. When the cache manager has determined that the data will no longer be needed for a certain amount of time, it writes the altered data back to the file on the disk, as shown by the dotted arrow between the system cache and the disk.
http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa364218(v=vs.85).aspx
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:23:56 am
По аналогии - в ББ весь кэш 8 КБ на каждый файл, т.к. состоит из 4 буферов по 2 КБ
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 11:25:20 am
И кроме того, valexey, управление файлами и буферами во всех Оберонах одинаковое. В этом то и странность.
Ну, а что такого странного? Что 1024 что 4096 буфер будет работать лучше чем без буфера вообще (в случае если мы работаем поверх ОС). Впрочем, также неплохо будет работать и буфер размером в 1234 байта (но немного хуже, но чтобы это самое немного хуже обнаружить, придется сильно извратиться). Ибо экономим на syscall'ах. То есть выбор не принципиален для очень многих задач.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:30:51 am
Странно что он такой маленький и фиксированный.
Размер 2 КБ ни туда ни сюда. Не оставили же они 1 КБ как в оригинале...
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:36:31 am
Т.е. для уменьшения частоты обмена с системным буфером логичнее было бы делать пользовательский буфер больше (32КБ - 64КБ), но они этого не сделали, и даже сделали размер неизменным...
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 11:38:25 am
Странно что он такой маленький и фиксированный.
Размер 2 КБ ни туда ни сюда. Не оставили же они 1 КБ как в оригинале...
Изучая исключительно io-шедулер NT ты не поймешь почему в ББ сделано именно так. Просто потому, что ББ не затачивался под NT.

ББ затачивался под Win9x и MacOS (классику). Поэтому, видимо, следует смотреть что было с кешированием там, и что там было с FS.

То есть решение по этой константе было принято когда-то тогда. Решение не менялось просто потому, что ни разу не встретилась задача, где это выстрелило бы.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 11:41:34 am
Т.е. для уменьшения частоты обмена с системным буфером логичнее было бы делать пользовательский буфер больше (32КБ - 64КБ), но они этого не сделали, и даже сделали размер неизменным...
Палка о двух концах. Во-первых 64 Кб это уже много. Это ж буфер на один файл. Открой 100 файлов, и получи 6.4 Мб затрат ОЗУ. Это дофига, между прочим. Это  больше чем воткнуто в типичную машину!

Во-вторых большой буфер - это больше вероятность потерять данные в случае падения приложения.
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 11:42:23 am
Моё предположение таково: размер кеша имеет прямое отношение и к размеру кластера на ФС. Который может быть 1кб и выше - зависит от нужды хранить много мелких файлов, для наиболее эффективного использования дискового пространства. А системный буфер является прослойкой между разнящимися размерами кластера и API чтения с файла. То есть он заведомо больше размера сектора.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 11:48:19 am
Моё предположение таково: размер кеша имеет прямое отношение и к размеру кластера на ФС. Который может быть 1кб и выше - зависит от нужды хранить много мелких файлов, для наиболее эффективного использования дискового пространства. А системный буфер является прослойкой между разнящимися размерами кластера и API чтения с файла. То есть он заведомо больше размера сектора.
Размер кластера может быть 512 байт.
Можно сделать буфер размером в 1234 байта, существенной разницы с 1024 не будет. Скорее всего будет быстрее. Впрочем, это легко проверить.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:53:59 am
В ориг. Обероне будет существенная разница (в худшую сторону), а в ББ скорее всего нет (буфер то пользовательский). А при отключенном системном буфере венда вообще не даст так сделать :)
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:54:50 am
Romiras, а ты не сравнивал случайно FPC и ББ по скорости I/O?
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 11:56:49 am
Т.е. для уменьшения частоты обмена с системным буфером логичнее было бы делать пользовательский буфер больше (32КБ - 64КБ), но они этого не сделали, и даже сделали размер неизменным...
Палка о двух концах. Во-первых 64 Кб это уже много. Это ж буфер на один файл. Открой 100 файлов, и получи 6.4 Мб затрат ОЗУ. Это дофига, между прочим. Это  больше чем воткнуто в типичную машину!

Во-вторых большой буфер - это больше вероятность потерять данные в случае падения приложения.
Ну да, многовато. Но это зависит от задачи. А в ББ свой размер нельзя задать. Что не есть гуд.
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 12:01:45 pm
Romiras, а ты не сравнивал случайно FPC и ББ по скорости I/O?
Нет. А на примере чего?
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 12:05:25 pm
Размер кластера может быть 512 байт.
Были и такие времена. Но уже, как правило, не меньше 4096 по умолчанию. Впрочем, это зависит от того какого размера данные будут на этой ФС и задаётся при форматировании раздела.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:06:50 pm
Моё предположение таково: размер кеша имеет прямое отношение и к размеру кластера на ФС. Который может быть 1кб и выше - зависит от нужды хранить много мелких файлов, для наиболее эффективного использования дискового пространства. А системный буфер является прослойкой между разнящимися размерами кластера и API чтения с файла. То есть он заведомо больше размера сектора.
Размер кластера может быть 512 байт.
Можно сделать буфер размером в 1234 байта, существенной разницы с 1024 не будет. Скорее всего будет быстрее. Впрочем, это легко проверить.

Все. Проверил. Результаты ровно те, которые я ранее предсказывал:
Код:
package main

import "fmt"
import "os"
import "bufio"

func main() {
file, err := os.Create("hello2.txt")
if err!= nil {
fmt.Print(err)
return
}
w := bufio.NewWriterSize(file,1234)
for i:=0; i<100000000; i++ {
fmt.Fprintf(w, "a")
}
}

Собственно тут 1234 -- это та самая циферька которую будем менять.

Провел эксперимент с размером буфера в 1024, 16, и 1234 байта.

Результаты:
1024:
Цитировать
ETime(   0:00:22.840 ) UTime(   0:00:22.448 ) KTime(   0:00:00.358 )
ITime(   0:00:00.000 )

16:
Цитировать
ETime(   0:00:39.146 ) UTime(   0:00:28.704 ) KTime(   0:00:10.405 )
ITime(   0:00:00.000 )

1234:
Цитировать
ETime(   0:00:22.647 ) UTime(   0:00:22.323 ) KTime(   0:00:00.265 )
ITime(   0:00:00.000 )

Ну и, до кучи, попробую сейчас 4096 сделать. Думаю что особой разницы с 1234 и 1024 не будет.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:10:05 pm
1234:
Цитировать
ETime(   0:00:22.647 ) UTime(   0:00:22.323 ) KTime(   0:00:00.265 )
ITime(   0:00:00.000 )

Ну и, до кучи, попробую сейчас 4096 сделать. Думаю что особой разницы с 1234 и 1024 не будет.

Ну, собственно вот:
Цитировать
ETime(   0:00:22.081 ) UTime(   0:00:21.855 ) KTime(   0:00:00.202 )
ITime(   0:00:00.000 )

А если не видно разницы, зачем платить больше? :-)
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 12:12:45 pm
Romiras, а ты не сравнивал случайно FPC и ББ по скорости I/O?
Нет. А на примере чего?
Ну вот к примеру как valexey выше проверил на Гоше
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 12:13:06 pm
valexey, твой аппликативный буфер не имеет прямого отношения к буферу API, который обращается напрямую к файловой системе. Следовательно, разницы в результатах быть и не должно.
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 12:15:32 pm
Romiras, а ты не сравнивал случайно FPC и ББ по скорости I/O?
Нет. А на примере чего?
Ну вот к примеру как valexey выше проверил на Гоше
Не должно зависеть от выбранного ЯП. Только от реализации системных вызовов.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:15:48 pm
valexey, твой аппликативный буфер не имеет прямого отношения к буферу API, который обращается напрямую к файловой системе. Следовательно, разницы в результатах быть и не должно.
Напрямую к FS обращается вообще то драйвер. То есть это ровно то, что не имеет отношения к тому что в ББ проставлено.

Изначально мы говорили о буфере который сидит на стороне приложения а не ОСи. Советую внимательно перечитать дискуссию.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 12:16:50 pm
А если не видно разницы, зачем платить больше? :-)

Я на BB тоже вчера проверял (только на чтение 1,8ГБ)  :)
2 - 28876 миллисек
4 - 27846 миллисек
8 -  27815 миллисек
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:17:27 pm
Не должно зависеть от выбранного ЯП. Только от реализации системных вызовов.
Дьявол в нюансах.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:20:13 pm
А если не видно разницы, зачем платить больше? :-)

Я на BB тоже вчера проверял (только на чтение 1,8ГБ)  :)
2 - 28876 миллисек
4 - 27846 миллисек
8 -  27815 миллисек
2 - это 2 Кб, или таки 2 байта?

И как читалось - побайтово, или как-то иначе? Тут есть разница. Если не сложно, то неплохо бы привести код (чтобы другие у себя могли проверить)
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 12:21:58 pm
Надо понимать, что между этапом где данные, находящиеся на жестком диске, и этапом их проекции в память лежат несколько прослоек, начиная от драйвера ФС, обращающегося к ФС и до аппликации, использующей системные вызовы. А программный буфер - это штука чисто виртуальная. Она должна влиять лишь на объём потребляемой памяти программой.
Таковы мои соображения.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:24:35 pm
Кстати, свой эксперимент я признаю неудовлетворительным. Fprintf слишком долго думает самостоятельно. Заменил на тупой вызов WriteByte - стало работать в 20 раз быстрее.

Так что сейчас будет серия новых экспериментов.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 12:26:02 pm
А программный буфер - это штука чисто виртуальная. Она должна влиять лишь на объём потребляемой памяти программой.
Таковы мои соображения.

Оставленное в цитате - не правильные соображение. Програмный буфер значительно влияет на производительность за счет снижения числа системных вызовов - системный вызов это большие тормоза.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 12:32:08 pm
В HostFiles меняем размер буфера и линкуем новый exe'шник BB.

Читаются побайтово файлы из папки с:\temp:

MODULE ilovbTestIO;
    IMPORT
        Log, Files, HostFiles;

    PROCEDURE Do*;
        VAR
            loc: Files.Locator;
            file: Files.File;
            list: Files.FileInfo;
            rd: Files.Reader;
            b: BYTE;
    BEGIN
        loc := HostFiles.NewLocator("c:\temp\");
        list := Files.dir.FileList(loc);
        WHILE list # NIL DO
            file := Files.dir.Old(loc, list.name, Files.shared);
            rd := file.NewReader(NIL);
            rd.SetPos(0);
            REPEAT
                rd.ReadByte(b);
            UNTIL rd.eof;
            list := list.next;
        END;
       
    END Do;
   
BEGIN
END ilovbTestIO.
^Q DevProfiler.Execute ilovbTestIO.Do

^Q DevLinker.Link
BlackBox4.exe := Kernel$+ Files HostFiles StdLoader
1 Applogo.ico 2 Doclogo.ico 3 SFLogo.ico 4 CFLogo.ico 5 DtyLogo.ico
1 Move.cur 2 Copy.cur 3 Link.cur 4 Pick.cur 5 Stop.cur 6 Hand.cur 7 Table.cur
Название: Re: Буферизация ввода/вывода
Отправлено: Romiras от Январь 17, 2013, 12:41:37 pm
Програмный буфер значительно влияет на производительность за счет снижения числа системных вызовов
Под системным вызовом я понимаю вызов системного API. Он, в свою очередь, должен обеспечивать чтение блоков данных без задержек, при помощи внутреннего (системного) буфера.

Далее. Касательно побайтового чтения. Это лишь установка позиции в программном буфере. Так что не должно влиять на скорость чтения данных.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 12:42:54 pm
Далее. Касательно побайтового чтения. Это лишь установка позиции в программном буфере. Так что не должно влиять на скорость чтения данных.
+1
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 12:44:38 pm
2 - это 2 Кб, или таки 2 байта?
КБ
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 01:39:28 pm
А программный буфер - это штука чисто виртуальная. Она должна влиять лишь на объём потребляемой памяти программой.
Таковы мои соображения.

Оставленное в цитате - не правильные соображение. Програмный буфер значительно влияет на производительность за счет снижения числа системных вызовов - системный вызов это большие тормоза.

Исправляюсь. Теперь эксперимент более чистый. Причем на чтение.

Буфер у меня, как понимаете, програмный. На стороне приложения. К системе отношения не имеющий.

Исходник такой:
package main

import "fmt"
import "os"
import "bufio"

func main() {
file, err := os.Open("1000000000.txt")
if err!= nil {
fmt.Print(err)
return
}
r := bufio.NewReaderSize(file,16)
for i:=0; i<1000000000; i++ {
r.ReadByte()
}
}

Вариация для чтения без буфера:
func main() {
file, err := os.Open("1000000000.txt")
if err!= nil {
fmt.Print(err)
return
}
var buf []byte = make([]byte, 1)
for i:=0; i<1000000000; i++ {
file.Read(buf)
}
}

Результаты:
64*1024:
Цитировать
ETime(   0:00:07.977 ) UTime(   0:00:07.456 ) KTime(   0:00:00.499 )
ITime(   0:00:00.000 )

4096:
Цитировать
ETime(   0:00:08.935 ) UTime(   0:00:07.347 ) KTime(   0:00:01.591 )
ITime(   0:00:00.000 )

1234:
Цитировать
ETime(   0:00:11.981 ) UTime(   0:00:08.892 ) KTime(   0:00:03.010 )
ITime(   0:00:00.000 )

1031 (простое число):
Цитировать
ETime(   0:00:12.444 ) UTime(   0:00:08.034 ) KTime(   0:00:04.414 )
ITime(   0:00:00.000 )
Но тут все сложно на самом деле - время скачет при этом размере буфера довольно сильно - бывает что подскакивает аж до 17ти секунд.

1024:
Цитировать
ETime(   0:00:12.423 ) UTime(   0:00:08.236 ) KTime(   0:00:04.180 )
ITime(   0:00:00.000 )
А вот тут - стабильно. Похоже, прыжки - особенность простых чисел. Но это конечно требует дополнительного исследования.

1000 (кратно размеру файла (в байтах)):
Цитировать
ETime(   0:00:12.719 ) UTime(   0:00:08.860 ) KTime(   0:00:03.837 )
ITime(   0:00:00.000 )

907 (простое число)
Цитировать
ETime(   0:00:13.378 ) UTime(   0:00:09.172 ) KTime(   0:00:04.056 )
ITime(   0:00:00.000 )
Прыжков нет. Все стабильно. Ничего не понимаю.

400 байт:
Цитировать
ETime(   0:00:19.790 ) UTime(   0:00:10.264 ) KTime(   0:00:09.500 )
ITime(   0:00:00.000 )

16:
Цитировать
ETime(   0:05:27.683 ) UTime(   0:01:21.962 ) KTime(   0:03:52.878 )
ITime(   0:00:00.000 )

Без буфера (буфера приложения, системный кеш я не отключал, а отключить кеш самого hdd не представляется возможным) вообще. Поскольку я не смог дождаться на гигабайтном файле (точнее на 1000000000 байтном), я уменьшил размер в 100 раз:
Цитировать
ETime(   0:00:48.116 ) UTime(   0:00:10.561 ) KTime(   0:00:37.549 )
ITime(   0:00:00.000 )
Соответственно и времена нужно умножить на 100.

Итого сводная табличка:
Буфер Full T System T
65536 7.977 0,499
4096 8.935 1,591
1234 11.981 3.01
1031 12.444 4.414
1024 12.423 4.18
1000 12.719 3.837
907 13.378 4.056
400 19.939 9.874
16 327.683 232.878
0 48116.0 37549.0

Итак, програмный буфер (буфер который ничего не знает о ФС, который у нас в программе и про который ни ФС ни драйвер диска ни система ничего не знает) существенно влияет на производительность. Минимальный разумный размер такого буфера - порядка 1000 байт. И само это число не обязано быть степенью двойки. Единственное - следует избегать простых чисел.

Что-то осталось не ясным? :-)
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 01:48:29 pm
А самое оптимальное таки 4096  :D
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 01:50:23 pm
Что-то осталось не ясным? :-)
Ну в общем то все так, как и ожидалось.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 01:57:07 pm
А самое оптимальное таки 4096  :D
Ну, оно столь же оптимально, как и 4000 или там, не знаю, 4123 :-)

Ну и опять таки - все ж зависит от задачи. Кому то может 64К понадобиться. Все же оно дает выигрыш.

Вообще, мне нравится подход Go, точнее принятый в библиотеке Go'шной - вот есть файл, если нужен буферизированный ввод-вывод - вот тебе еще одна либа, прикручивай (в одну строчку) сверху буферизирующую насадку.

Таким образом каждая либа делает только что-то узкое (например работает с файлом, или занимается буферизацией), при этом их можно скрещивать получая что-то новое (например буферизированный ввод-вывод для файлов). Причем для каждого файла с которым ты работаешь можно все это проделать индивидуально. И размеры буфера будет индивидуально для каждого свой (если нужно).
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 05:30:12 pm
Ну и чтобы была понятна разница между наличием системного буфера и его отсутствием, отрезаем буферизацию полностью. Ну, то есть не полностью, но заставляем систему в буфере ничего не держать, и сразу писать на диск:

Буфер 16 байт:
Цитировать
ETime(   0:00:00.163 ) UTime(   0:00:00.031 ) KTime(   0:00:00.124 )
ITime(   0:00:00.000 )

Буфер 16 байт, fsync на каждый байт:
Цитировать
ETime(   0:01:06.595 ) UTime(   0:00:01.014 ) KTime(   0:00:16.380 )
ITime(   0:00:00.000 )

Без буфера (без bufio):
Цитировать
ETime(   0:00:02.256 ) UTime(   0:00:00.608 ) KTime(   0:00:01.653 )
ITime(   0:00:00.000 )

Без буфера (без bufio) и с fsync:
Цитировать
ETime(   0:13:58.277 ) UTime(   0:00:06.396 ) KTime(   0:02:05.721 )
ITime(   0:00:00.000 )

Сводная табличка (размер записываемого файла - мегабайт):
Buf size | fsync |  Time (sec)
---------+-------+------------
16       |   -   |   0.163
16       |   +   |  66.595
 0       |   -   |   2.256
 0       |   +   | 838.227

Как видим, Аксенов был прав - fsync это зло. А ведь именно так сконфигурирован MySql + innodb по умолчанию. Зато надежно :-)

Также видим, что собственный буфер спасает (разница на два порядка) даже если fsync работает (то есть системный буфер по сути не используется). А системный буфер спасает еще на пару порядков.

PS. Странное дело - если я создаю файл, и файл такой уже существует (а создаю я его с truncate), то время записи в два раза больше. И это вне зависимости от буферизации и fsync.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 05:49:24 pm
Также видим, что собственный буфер спасает (разница на два порядка) даже если fsync работает (то есть системный буфер по сути не используется). А системный буфер спасает еще на пару порядков.
Ошибочка. Собственный буфер дает, в данном случае, выигрыш на порядок а не на два. А если его сделать нормального размера, то на полтора порядка.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 06:18:48 pm
А как ты отключал системный буфер? Через WinAPI?
И почему 16 байт?
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 07:56:51 pm
Java tip: How to read files quickly (http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly)
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 08:18:21 pm
А как ты отключал системный буфер? Через WinAPI?
И почему 16 байт?
16 байт, потому что иначе программа будет работать слишком быстро на мегабайтном файле. :-)

Как отключил - я же написал все подробно. fsync.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 08:26:55 pm
Код (буфер 16 + fsync):
func main() {
file,err := os.Create("100Mb.txt")
if err!= nil {
fmt.Print(err)
return
}
w := bufio.NewWriterSize(file,16)
for i:=0; i<1000000; i++ {
w.WriteByte(byte(32))
file.Sync() // fsync
}
}

Строчку file.Sync() если закомментить - будет с системным буфером. Грубо говоря.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 08:29:51 pm
А file.Sync() делает обмен с диском только если буфер заполнен? Или как?

ps И с чего ты взял что оно в обход системного буфера работает?
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 08:37:10 pm
Вот пример прямого обмена с диском в винде:
http://www.codeproject.com/Articles/51678/Improve-responsiveness-in-Windows-with-the-FILE_FL
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 08:52:17 pm
А file.Sync() делает обмен с диском только если буфер заполнен? Или как?

ps И с чего ты взял что оно в обход системного буфера работает?
Я ничего ниоткуда не взял. fsync заставляет систему если что и было в буфере, скинуть из буфера это дело на диск. Если там ничего не было, то конечно ничего скинуто и не будет (но время на syscall конечно все равно будет потрачено).

Соответственно что происходит - кладем байт в системный буфер, затем говорим системе - сбрось все из буфера на диск. Этот байт пишется на диск. Это если без нашего буфера работать.

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

Факт, что система, когда её буфер пуст, при вызове fsync не обращается к диску, виден в отношении времен 4 и 2 строчки таблицы. Отношение равно 12,7, что хорошо согласуется (по порядку величины) с теоретическим отношением равным 16.

Понятно что с FILE_FLAG_NO_BUFFERING, но без fsync результаты будут несколько лучше. Но совсем немного. Не на порядок.
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 09:00:37 pm
Я наверно торможу, но из твоего сообщения так и не понял... fsync сбрасывает пользовательский буфер в системный или системный на диск?
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 09:05:31 pm
Оно?
http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa364439(v=vs.85).aspx

PROCEDURE CloseFile (f: File; VAR res: INTEGER);
        VAR s: INTEGER;
    BEGIN
        IF f.state = exclusive THEN
            f.Flush;
            res := WinApi.FlushFileBuffers(f.ref)
         END;
        s := f.state; f.state := closed;
        CloseFileHandle (f, res);
        IF (s IN {temp, new, hidden}) & (f.name # "") THEN
            res := WinApi.DeleteFileW(f.name)
        END
    END CloseFile;
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 09:07:15 pm
Я наверно торможу, но из твоего сообщения так и не понял... fsync сбрасывает пользовательский буфер в системный или системный на диск?
Системный на диск, если он не пуст. Если пуст, то обращения к диску не будет.

А содержимое пользовательского буфера будет насильно сброшено в системный с помощью fflush (в данном случае w.Flush())

Две забавные штучки fflush и fsync :-) Советую таки посмотреть видео доклада Аксенова по MySql - он это все очень хорошо описывает.
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 09:12:52 pm
Оно?
http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa364439(v=vs.85).aspx

PROCEDURE CloseFile (f: File; VAR res: INTEGER);
        VAR s: INTEGER;
    BEGIN
        IF f.state = exclusive THEN
            f.Flush;
            res := WinApi.FlushFileBuffers(f.ref)
         END;
        s := f.state; f.state := closed;
        CloseFileHandle (f, res);
        IF (s IN {temp, new, hidden}) & (f.name # "") THEN
            res := WinApi.DeleteFileW(f.name)
        END
    END CloseFile;

Да, оно.

func (f *File) Sync() (err error) {
if f == nil {
return syscall.EINVAL
}
if e := syscall.Fsync(f.fd); e != nil {
return NewSyscallError("fsync", e)
}
return nil
}

...

func Fsync(fd Handle) (err error) {
return FlushFileBuffers(fd)
}

...

func FlushFileBuffers(handle Handle) (err error) {
r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
err = error(e1)
} else {
err = EINVAL
}
}
return
}

...

procFlushFileBuffers                 = modkernel32.NewProc("FlushFileBuffers")
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 09:14:06 pm
Теперь вроде понятно.  :)

ps Делись ссылкой
Название: Re: Буферизация ввода/вывода
Отправлено: valexey_u от Январь 17, 2013, 09:18:30 pm
Теперь вроде понятно.  :)

ps Делись ссылкой
Дык я делился же уже :-)
Вот: http://addconf.ru/event.sdf/ru/add_3/authors/AndrewAksyonoff/732
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 17, 2013, 09:27:10 pm
Сенкс.

На всякий случай, чтобы избежать недоразумений:
http://oberspace.dyndns.org/index.php/topic,431.msg13629.html#msg13629
Картинка с цитатой из "Проект Оберон" - это конкретно про файлы в памяти (MFiles). Но думаю понятно что - это в равной степени справедливо и для файлов на диске. Тем более что реализация файлов на диске отличается лишь способом транспортировки байтов  :) Для файлов в памяти SYSTEM.MOVE, а для файлов на диске Kernel.PutSector
Название: Re: Буферизация ввода/вывода
Отправлено: ilovb от Январь 18, 2013, 04:24:56 pm
Вот: http://addconf.ru/event.sdf/ru/add_3/authors/AndrewAksyonoff/732
Прикольный чувак. Спасибо. Интересный доклад.