Как реализовать или эмулировать MADV_ZERO?
Я хотел бы иметь возможность обнулить диапазон отображения файловой памяти, не вызывая никакого ввода-вывода (для того, чтобы эффективно последовательно перезаписывать огромные файлы, не вызывая никакого чтения с диска).
дела std::memset(ptr, 0, length)
приведет к тому, что страницы будут прочитаны с диска, если их еще нет в памяти, даже если все страницы будут перезаписаны, что приведет к снижению производительности диска.
Я хотел бы иметь возможность сделать что-то вроде madvise(ptr, length, MADV_ZERO)
который обнулит диапазон (аналогично FALLOC_FL_ZERO_RANGE
), чтобы вызвать сбои страницы заполнения нуля вместо обычных сбоев страницы io при доступе к указанному диапазону.
к несчастью MADV_ZERO
не существует Хотя соответствующий флаг FALLOC_FL_ZERO_RANGE
существует в fallocate
и может быть использован с fwrite
добиться аналогичного эффекта, хотя и без мгновенной кросс-когерентности процесса.
Я полагаю, что одной из возможных альтернатив является использование MADV_REMOVE
, Однако, насколько я понимаю, это может привести к фрагментации файла, а также к блокированию других операций при завершении, что не позволяет мне быть уверенным в его долгосрочных последствиях для производительности. Мой опыт работы с Windows заключается в том, что подобное FSCTL_SET_ZERO_DATA
Команда может вызвать значительные скачки производительности при вызове.
Мой вопрос заключается в том, как можно реализовать или подражать MADV_ZERO
для общих сопоставлений, предпочтительно в пользовательском режиме?
1. /dev/zero/
Я прочитал это предлагается просто прочитать /dev/zero
в выбранный диапазон. Хотя я не совсем уверен, что означает "чтение в диапазон" и как это сделать. Это как fread
от /dev/zero
в диапазон памяти? Не уверен, как это позволит избежать обычной ошибки страницы при доступе?
Для Linux просто прочитайте
/dev/zero
в выбранный диапазон. Ядро уже оптимизирует этот случай для анонимных сопоставлений.Если делать это в целом оказывается слишком сложно для реализации, я
Предлагаю MADV_ZERO должен иметь такой эффект: точно так же, как чтение
/dev/zero в диапазоне, но всегда эффективен.
РЕДАКТИРОВАТЬ: После того, как поток немного дальше, оказывается, что он на самом деле не будет работать.
Он не делает трюков, когда вы имеете дело с общим отображением.
2. MADV_REMOVE
Одним из предположений о его реализации в Linux (т.е. не в пользовательском приложении, что я бы предпочел) может быть простое копирование и изменение MADV_REMOVE
т.е. madvise_remove
использовать FALLOC_FL_ZERO_RANGE
вместо FALLOC_FL_PUNCH_HOLE
, Хотя я не совсем понимаю, как это угадать, тем более что я не совсем понимаю, что за код вокруг vfs_allocate
делается:
// madvice.c
static long madvise_remove(...)
...
/*
* Filesystem's fallocate may need to take i_mutex. We need to
* explicitly grab a reference because the vma (and hence the
* vma's reference to the file) can go away as soon as we drop
* mmap_sem.
*/
get_file(f); // Increment ref count.
up_read(¤t->mm->mmap_sem); // Release a read lock? Why?
error = vfs_fallocate(f,
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, // FALLOC_FL_ZERO_RANGE?
offset, end - start);
fput(f); // Decrement ref count.
down_read(¤t->mm->mmap_sem); // Acquire read lock. Why?
return error;
}
1 ответ
Вы, вероятно, не можете делать то, что вы хотите (в пространстве пользователя, без взлома ядра). Обратите внимание, что запись нулевых страниц может не повлечь за собой физический дисковый ввод-вывод из-за кеша страниц.
Возможно, вы захотите заменить сегмент файла на дыру в файле (но это не совсем то, что вам нужно) в разреженном файле, но некоторые файловые системы (например, VFAT) не имеют дыр или разреженных файлов. Смотрите lseek(2) с SEEK_HOLE
, ftruncate (2)