C Дисковый ввод-вывод — запись после чтения по тому же смещению файла сделает скорость чтения очень низкой

Фон:

Я разрабатываю программу, связанную с базой данных, и мне нужно последовательно сбрасывать грязные метаданные из памяти на диск. /dev/sda1 — это формат volumn, поэтому доступ к данным в /dev/sda1 будет осуществляться поблочно, а при последовательном доступе блоки будут физически соседними. И я использую прямой ввод-вывод, поэтому ввод-вывод будет обходить механизм кэширования файловой системы и напрямую обращаться к блокам на диске.

Проблемы:

После открытия /dev/sda1 я прочитаю один блок, обновлю блок и запишу блок обратно с тем же смещением от начала /dev/sda1, итеративно.

Код выглядит следующим образом:

//block_size = 256KB
int file = open("/dev/sda1", O_RDWR|O_LARGEFILE|O_DIRECT);
for(int i=0; i<N; i++) {
    pread(file, buffer, block_size, i*block_size);
    // Update the buffer
    pwrite(file, buffer, block_size, i*block_size);
}

Я обнаружил, что если не выполнять pwrite, скорость чтения составляет 125 МБ/с.

Если я выполню pwrite, скорость чтения будет 21 МБ/с, а скорость записи — 169 МБ/с.

Если я выполняю pread после pwrite, скорость записи составляет 115 МБ/с, а скорость чтения составляет 208 МБ/с.

Я также пробовал read()/write() и aio_read()/aio_write(), но проблема осталась. Я не знаю, почему запись после чтения в одной и той же позиции файла делает скорость чтения такой низкой.

При доступе к большему количеству блоков за раз, как это

pread(file, buffer, num_blocks * block_size, i*block_size);

Проблема устранится, см. диаграмму.


person Chia    schedule 23.09.2015    source источник
comment
Какой у вас размер блока? Есть большая вероятность, что вы видите эффекты аппаратного кэширования и упреждающего чтения на дисках, к которым вы обращаетесь. pwrite() заполняет кеш, и если следующие pread() предназначены для других данных, ни один из них не кэшируется. Выполнение pread() после pwrite() позволяет считывать данные непосредственно из аппаратного кэша диска.   -  person Andrew Henle    schedule 23.09.2015
comment
Я не знаю физический размер блока, и я установил в программе 256 КБ. Спасибо за ваш комментарий, теперь я думаю, что это, скорее всего, вызвано буфером диска.   -  person Chia    schedule 23.09.2015


Ответы (1)


И я использую прямой ввод-вывод, поэтому ввод-вывод будет обходить механизм кэширования файловой системы и напрямую обращаться к блокам на диске.

Если у вас нет файловой системы на устройстве и вы напрямую используете устройство для чтения/записи, то кэш файловой системы не возникает.

Поведение, которое вы наблюдали, типично для доступа к диску и поведения ввода-вывода.

Я обнаружил, что если я не делаю pwrite, скорость чтения составляет 125 МБ/с.

Причина: Диск просто читает данные, ему не нужно возвращаться к смещению и записывать данные, на 1 операцию меньше.

Если я выполню pwrite, скорость чтения будет 21 МБ/с, а скорость записи — 169 МБ/с.

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

Если я выполняю pread после pwrite, скорость записи составляет 115 МБ/с, а скорость чтения — 208 МБ/с.

Причина: Скорее всего, записываемые данные кэшируются на уровне диска, поэтому чтение получает данные из кэша, а не с носителя.

Чтобы получить оптимальную производительность, вы должны использовать асинхронные операции ввода-вывода и несколько блоков одновременно. Однако вы должны использовать разумное количество блоков и не можете использовать очень большое количество. Следует выяснить, что является оптимальным методом проб и ошибок.

person Rohan    schedule 23.09.2015
comment
Спасибо за ваш ответ, теперь я думаю, что это, скорее всего, вызвано буфером диска. Но я до сих пор не могу себе представить, что просто переход на предыдущую позицию позволит снизить пропускную способность чтения со 125 МБ/с до 21 МБ/с... - person Chia; 23.09.2015
comment
@leo, да, поиски дорогие. Посмотрите на время ожидания ввода-вывода, которое будет увеличиваться при снижении пропускной способности. - person Rohan; 23.09.2015