почему чтение происходит быстрее при использовании флага O_DIRECT?
Я скопировал файл объемом 10 ГБ на свой твердотельный накопитель, пропускная способность чтения которого составила около 3,3 ГБ/с, измеренная с помощью команды fio. Вот ссылка: https://cloud.google.com/compute/docs/disks/benchmarking-pd- Performance.
Я очистил кеш, используя эту «sync; echo 3 > /proc/sys/vm/drop_caches». После этого я каждый раз пытался читать файл небольшими порциями по 3 МБ, используя системные вызовы open() и read(). Если я открою файл без O_DIRECT и O_SYNC, это даст мне пропускную способность около 1,2 ГБ/с. Однако если я использую O_DIRECT и O_SYNC, это дает мне пропускную способность около 3 ГБ/с. Очистка кеша оба раза, даже O_DIRECT на самом деле не использует кеш страницы.
Мой вопрос: почему O_DIRECT обеспечивает нормальную пропускную способность ввода-вывода, а без O_DIRECT я не могу ее получить. Поскольку данные, поступающие из ввода-вывода в страничный кэш, имеют пропускную способность 3,3 ГБ/с, а из страничного кэша в пользовательский буфер — около 7 ГБ/сек. Этот конвейер также должен давать нормальные 3,3 ГБ/с. Почему он медленнее?
Я всегда читаю новые 3 МБ каждый раз. Я не использую данные повторно, поэтому кэш бесполезен. Но конвейер должен быть привязан к IO, почему это не так?
Процессор — Intel(R) Xeon(R) Silver 4214 с частотой 2,20 ГГц. Я не уверен насчет скорости DRAM. Но дело в том, что если я перечитаю одни и те же 3 МБ несколько раз, то получу пропускную способность ~8 ГБ/с. Я полагаю, какой должна быть пропускная способность DRAM. Потому что Linux может использовать всю свободную оперативную память в качестве страничного кэша.
Обновлять
Я попробовал команду fio с включенным O_DIRECT и без него и зарегистрировал iostat.
Использовал эту команду fio. "fio --name=read_throughput --directory=$TEST_DIR --numjobs=1 --size=10G --time_based --runtime=30s --ramp_time=0s --ioengine=sync --direct=0 --verify=0 --bs=4K --iolength=1 --rw=read --group_reporting=1 --ioDPse_batch_submit=64 --ioDepth_batch_complete_max=64"
Использовал этот iostat.
"iostat -j ID nvme0c0n1 -x 1"
Я пришел к следующему выводу: однопоточное чтение без флага O_DIRECT не может насытить SSD достаточным количеством запросов на чтение для достижения скорости 3,3 ГБ/с независимо от используемого размера блока. Однако с помощью O_DIRECT falg однопоточное чтение может перегрузить устройство, когда размер блока составляет 64 МБ или выше. У 3M это около 2,7 ГБ/с.
Теперь вопрос в том, почему без флага O_DIRECT процессор не может отправлять достаточное количество запросов на чтение на SSD, почему он их ограничивает? Связано ли это с ограничением управления кешем? Если да, то какой параметр ограничивает это? Могу ли я изменить его и посмотреть, повлияет ли это на количество запросов на чтение, отправляемых на устройство?
1 ответ
O_DIRECT быстрее, чем обычное чтение, поскольку оно обходит буферы операционной системы. Вы читаете прямо с диска. Есть несколько причин, по которым это может быть быстрее, но имейте в виду, что на этом уровне все очень сильно зависит от настроек. Пример того, что я имею в виду под конкретными факторами настройки: если у вас есть диск, оптимизированный для записи 8 КБ внутри фрагментов NAND, а не 4 КБ, и вы пишете/читаете неправильный размер, вы увидите половину производительности, но для этого вам потребуется внутренний понимание того, как работают приводы. Это может даже варьироваться в пределах одной и той же модели - например: модель диска A может иметь разные оптимизации, чем та же модель диска B (я видел это несколько раз в полевых условиях).
Но вернемся к вашему вопросу:
- Нет кеша, который нужно копировать туда и обратно
- Если вы делаете что-то вроде FIO, вы получите более предсказуемое поведение при чтении.
- 1 МБ — это большой размер блока, поэтому вы получите дополнительную выгоду, не имея дело с кешем.
Помимо этого вам нужно начать глубже изучать бенчмаркинг, а это довольно сложная тема.
Моя общая рекомендация — начать с
Однако то, что я сказал в начале, может привести вас к цели. Лучше всего предположить, что если вы выполняете чтение больших блоков, вы экономите на некоторой неэффективности кэша.