LINUX.ORG.RU

Оптимизация ввода-вывода


0

0

Мне в процессе работы программы необходимо прочитать файл размером
порядка 2 гб, а потом записать в другой файл. Читаю и пишу я через
stdio блоками по 100 байт. Секундомер показал что примерно половину
времени я трачу на работу с диском. Можно ли уменьшить время
ввода-вывода увеличив размер читаемого(записываемого) блока?


На простом тесте :
// test1
int main()
{
char buf[100];
FILE * fp = fopen("input","rb");
while(!feof(fp))
{
fread(buf,1,100,fp);
}
return 0;
}

// test2
int main()
{
char buf[1000000];
FILE * fp = fopen("input","rb");
while(!feof(fp))
{
fread(buf,1,1000000,fp);
}
return 0;
}

особого различия я не заметил.

★★

Читай данные объемом кратным размеру блока (обычно, 1024б покатит). Ну, конечно, можно делать это непосредственно read/write -ом, читать побольше, чтоб делать поменьше системных вызовов и чтоб система сама смогла оптимизировать чтение большого объема данных. Но все это, конечно, не даст 10 кратного прироста производительности...

anonymous
()
Ответ на: комментарий от watashiwa_daredeska

>Откажись от stdio. Используй open/read/write.

А можно подробней, что мне это даст в практическом плане, кроме возможной непереносимости?

Я полагал, что stdio использут буферизацию и тем самым уменьшает количество обращений к диску, а использование read/write это гаранитированое обращение к диску при каждом вызове.... Я не прав?

Vinick ★★
() автор топика
Ответ на: комментарий от Vinick

> Я полагал, что stdio использут буферизацию

верно, именно поэтому вы и не видите большой разницы
между buf[100] и buf[1000000], просто fread() вызывается
чаще.

> и тем самым уменьшает количество обращений к диску,

уменьшается количество вызовов read() из fread()

> а использование read/write это гаранитированое обращение к
> диску

нет, это гарантированный вход в ядро. чтение с диска
будет если страницы нет в page cache. в вашем случае,
если ее не успел прочитать readahead.

посколько ваша программа ничего не делает, вы не получите
ускорения поменяв fread() на read(). в любом случае доступ
будет ограничен скоросьтю чтения с диска. в случае с fread
у вас лишние расходы на копирование данных, но это все равно
на порядки быстрее чем диск.

idle ★★★★★
()
Ответ на: комментарий от idle

> в любом случае доступ будет ограничен скоросьтю чтения с диска. в
> случае с fread у вас лишние расходы на копирование данных, но это все
> равно на порядки быстрее чем диск.

То есть все, что я могу сделать здесь в плане оптимизации - это
уменьшить количество системных вызовов?


Vinick ★★
() автор топика
Ответ на: комментарий от Vinick

> То есть все, что я могу сделать здесь в плане оптимизации - это
> уменьшить количество системных вызовов?

если говорить о том, сколько времени будет выполняться
программа, то - дa.

однако, вы может уменьшить количество CPU потребляемое
вашей программой
    1. уменьшить количество syscall'ов увеличив буфер.
    2. сделав буфер кратным размеру страницы

слишком большой буфер делать не надо - будет нагрузка на
cache.

idle ★★★★★
()

Разница по времени между dd if=file1 of=file2 bs=1024 и dd if=file1 of=file2 bs=1024K составляет порядка 500% (да, да, да, разница ПЯТИКРАТНАЯ как минимум).

Кэш stdio совершенно номинальный, на него не стоит надеяться.

no-dashi ★★★★★
()
Ответ на: комментарий от idle

>слишком большой буфер делать не надо - будет нагрузка на cache.

но программа имеющая буфер 512кБ МОЖЕТ работать существенно быстрее чем программа имеющая буфер 512 байт

cvv ★★★★★
()
Ответ на: комментарий от no-dashi

> Разница по времени между dd if=file1 of=file2 bs=1024 и dd if=file1 of=file2 bs=1024K
> составляет порядка 500%

а теперь еще раз прочитайте то, что я написал раньше.

и попробуйте указать of=/dev/null

и убедитесь, что размер файла значительно превосходит
размер RAM.

idle ★★★★★
()
Ответ на: комментарий от no-dashi

>Разница по времени между dd if=file1 of=file2 bs=1024 и dd if=file1 of=file2 bs=1024K составляет порядка 500% (да, да, да, разница ПЯТИКРАТНАЯ как минимум).

Дело в том, что автор изначального поста тестировал только чтение. Соответственно, файл с диска читается в любом случае последовательно. Если хочется, чтобы эксперимент с dd соответствовал приведенному тесту с fread, то писать нужно в /dev/null, и никакой пятикратной разницы не будет.

Другое дело, что автор поста, скорее всего, не читает файл в память целиком, а чередует чтение и запись, так что его эксперименты с fread не кажутся вполне удачными и имеющими отношение к делу.

Еще мне непонятен тезис автора о возможных проблемах совместимости при использованиии open/read.

anonymous
()
Ответ на: комментарий от cvv

> но программа имеющая буфер 512кБ МОЖЕТ работать существенно
> быстрее чем программа имеющая буфер 512 байт

может. а может и медленнее стать. зависит от задачи.

idle ★★★★★
()
Ответ на: комментарий от no-dashi

>Кэш stdio совершенно номинальный, на него не стоит надеяться.

man setvbuf

anonymous
()
Ответ на: комментарий от anonymous

> Соответственно, файл с диска читается в любом случае
> последовательно.

не только в этом дело, хотя и в этом тоже.

когда процесс делает write(), это требует времени.
за это время readahead уже может (должен) прочитать
данные, которые требуются для следующего read() и
они уже будут в page cache.

иными словами, в данном случае процесс что-то _делает_
с данными (пишет их), и это что-то может быть медленнее
доступа к диску.

> то писать нужно в /dev/null, и никакой пятикратной разницы
> не будет.

именно.

idle ★★★★★
()
Ответ на: комментарий от anonymous

>Другое дело, что автор поста, скорее всего, не читает файл в память целиком, а чередует чтение и запись, так что его эксперименты с fread не кажутся вполне удачными и имеющими отношение к делу.

Я последоваельно считываю в память примерно пятую часть общего объема данных и только после этого начинаю запись его на диск. После чего читаю следующую порцию и т.д.

>Еще мне непонятен тезис автора о возможных проблемах совместимости при использованиии open/read

Да, это я действительно неподумавши сказал. :)

Vinick ★★
() автор топика
Ответ на: комментарий от idle

> то писать нужно в /dev/null, и никакой пятикратной разницы не будет.

Ну если надо _только_ читть, тогда конечно да, пятикратной разницы не будет (хотя чистые 20% в плюч пойдет). Проблемы начнутся, когда читают несколько процесоов одновременно. И неужели все забыли, что все современные девайсы давно работают операциями размером в разы больше размера одного блока?

no-dashi ★★★★★
()
Ответ на: комментарий от no-dashi

когда-то мне понравилась подобная дискуссия в Qtях
http://lists.trolltech.com/qt-interest/1999-11/thread00248-0.html

было предложено:
int copyfile(const char *from, const char *to)
{
FILE *inf, *outf;
char buf[16384];
int r, ret;

if(!(inf = fopen(from, "rb"))) return -1;
if(!(outf = fopen(to, "wb"))) {
fclose(inf);
return -1;
}
while((r = fread(buf, 1, sizeof(buf), inf)) > 0
&& fwrite(buf, 1, r, outf) == r)
;
ret = 0;
if(ferror(inf) || ferror(outf))
ret = -1;
if((fclose(inf) != 0) | (fclose(outf) != 0))
ret = -1;
return ret;
}

И в конце сказано:
"
If you look at Steven's book on UNIX (Advanced Unix System Programming [I
think]) he shows how buffer size efffects the speed of this copy. It
becomes a function of the disk block size so 16k is probably a good number
to use, i.e. a bigger buffer won't make it any faster.
"

2idle: "16k is _optimal_" - так ли на самом деле?

Valeriy_Onuchin ★★
()
Ответ на: комментарий от Valeriy_Onuchin

>"16k is _optimal_" - так ли на самом деле?

для некоторого гипотетического устройства.

в реальной жизни сильно зависит от самого девайса. я бы брал на порядок больше.

cvv ★★★★★
()
Ответ на: комментарий от no-dashi

> пятикратной разницы не будет (хотя чистые 20% в плюч пойдет)

да откуда же возьмутся эти 20% ???

ну поймите же. dd if=file of=/dev/null
ну никак не сможет работать быстрее, чем
диск будет отдавать данные, то есть он
и будет работать с этой скоростью.

если при bs=1024 он работает на 20% медленнее,
это означает, что dd не успевает _игнорировать_
данные со скорость чтения с диска. 

> Проблемы начнутся, когда читают несколько процесоов
> одновременно.

поэтому я и писал о том, что имеет смысл уменьшить
потребляемое CPU.

> И неужели все забыли, что все современные девайсы давно работают
> операциями размером в разы больше размера одного блока?

это не играет роли абсолютно. даже если читать
по одному байту, readahead будет заряжать чтение
диска бОльшими блоками.

idle ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.