2016-09-20 12 views
0

Я знаю, что на жестком диске (обратите внимание, что речь идет о магнитных, а не в SSD), есть внутренние кеши для хранения на диске. Обычно они составляют около 64 МБ. Я пытаюсь понять, что такое типичная политика буферизации чтения для этих кешей.Кэш чтения на жестком диске на диске

Наивно, я предположил, что последние чтения кэшируются. Я попытался сделать простой тест на вторичном диске, Seagate ST32000645NS HDD, используя fio, а также небольшой фрагмент кода, который я написал. Этот диск даже не установлен, поэтому ничто не должно мешать этим тестам. Оба они многократно читаются из небольшого диапазона секторов (несколько МБ), которые хорошо содержатся в размере буфера на диске. Оба теста используют O_DIRECT для устранения эффектов буфера операционной системы. Поскольку современные дисковые интерфейсы имеют пропускную способность Gb/s, и все, кроме начальных чтений с диска, должны кэшироваться в буфере на диске, я ожидал увидеть пропускную способность 100 мб/с. Тем не менее, я получаю плохие результаты порядка 1 Мбайт/с, что указывает на то, что кэширование чтения не выполняется на диске. Я даже пытался многократно читать один и тот же 4 КБ снова и снова, и все же получил аналогичные плохие результаты.

Я посмотрел в dmesg, в котором говорится: «sd 1: 0: 0: 0: [sdb] Запись кеша: включена, читать кеш: включена, не поддерживает DPO или FUA». Таким образом, здесь не проблема конфигурации. Может ли кто-нибудь пролить свет на то, что может быть проблемой с кешем чтения на диске здесь? возможно, какая-то базовая конфигурация по умолчанию в драйвере говорит устройству игнорировать кеш чтения?

отредактировано - вот соответствующие фрагменты кода.

FIO код сценария, который я бегу несколько раз подряд:

[global] 
bs=4k 
rw=randread 
random_generator=lfsr 
direct=1 
ioengine=libaio 
iodepth=1 
direct=1 

[device] 
filename=/dev/sdb 
filesize=64M 
size=64M 

мой код:

char name[20] = "/dev/sdb"; 
int fd = open(name, O_RDWR | O_DIRECT); 
if (fd < 0){ 
    printf("failed openning %s. errno %d\n", name, errno); 
    return -1; 
} 

int pagesize=getpagesize(); 
printf("pagesize %d\n", pagesize); 

char* realbuff=malloc(4096+pagesize); 
char* buf=((((int unsigned)realbuff+pagesize-1)/pagesize)*pagesize); 

int res, off, total_reads = 100000; 
for (i=0; i<total_reads;i++){ 
    off = 0; 

    res = lseek(fd, off, SEEK_SET); 
    if (res != off){ 
     printf("seek res %d, expected %d\n. i %d errno %d", res, off, i, errno); 
     close(fd); 
     return -1; 
    } 

    res = read(fd, buf, pagesize); 
    if (res != pagesize){ 
     printf("read only %d bytes, expected %d\n. i %d errno %d", res, pagesize, i, errno); 
     close(fd); 
     return -1; 
    } 
} 
+0

Было бы более полезно, если вы покажете код, который вы написали, чтобы мы могли точно понять, что тестируется. В противном случае, единственное, что нам нужно пролить, - это ваша собственная интерпретация того, что вы тестируете. – paddy

+0

Спасибо, падди, я отредактировал в соответствии с вашим предложением. – user331398

+0

Есть ли причина, по которой вы используете 'O_RDWR'? Вы получаете схожую производительность, если вместо этого используете 'O_RDONLY'? – paddy

ответ

0

Обычно, используя O_DIRECT на малом I/размеры O работает плохо, поэтому, если вы хотите чтобы увидеть, что кеш чтения эффекта пытается выдавать большой ввод-вывод. Было бы полезно разделить fio тестовый сценарий или ваш тестовый код, чтобы помочь вам.

И, вы можете попробовать установить опцию упреждающего чтения в hdparam, который хорошо документированный в this link

---- обновленное ----

Так как прямого ввода/вывода можно рассматривать как синхронный I/O, I/O должен быть завершен до обработки входящих операций ввода-вывода. И небольшие входы/выходы занимают много времени при создании переключателей контекста и создании регистров для операций DMA.

В следующем графике показана пропускная способность прямого сценария ввода-вывода I/O. Я изменил размеры ввода-вывода с 4 КБ на 8 МБ, используя предоставленный сценарий fio. Поскольку это показывает, что выдача небольших размеров ввода-вывода с использованием прямого ввода-вывода показывает очень низкую производительность, а при увеличении размера ввода-вывода производительность также увеличивается.

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

direct I/O: file size 64MB, I/O size from 4 KB to 8MB

+0

Спасибо за вашу готовность помочь. Я отредактировал свой пост, чтобы включить соответствующие фрагменты кода (@paddy вы также просили об этом). Что касается O_DIRECT - я могу понять, почему O_DIRECT будет медленным для небольших чтений на жестком диске для небольших случайных доступов. Но если чтение предназначено для буферизованных данных, почему это важно? – user331398

+0

NB: прямой ввод-вывод может быть асинхронным в fio, если используемый ioengine является асинхронным. Вы можете увидеть это в действии в Linux при использовании ioengine = libaio --direct = 1 --iodepth = 16 против блочного устройства - глубина очереди, сообщенная fio при ее завершении, обычно будет больше 1. – Anon

0

ли повысит глубину, делая последовательно ввода/вывода и изменения размера (меньше и больше) разница? Wikipedia suggests the hard disk's cache is only used for readahead/readbehind and write caching. Если это так, вы не получите преимущества от кеша диска, который считывает только один случайный ввод-вывод в любой момент времени, даже если вы перечитываете одни и те же области.