Фон:
Я разрабатываю программу, связанную с базой данных, и мне нужно последовательно сбрасывать грязные метаданные из памяти на диск. /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);
Проблема устранится, см. диаграмму.
pwrite()
заполняет кеш, и если следующиеpread()
предназначены для других данных, ни один из них не кэшируется. Выполнениеpread()
послеpwrite()
позволяет считывать данные непосредственно из аппаратного кэша диска. - person Andrew Henle   schedule 23.09.2015