Как реализовать или эмулировать 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(&current->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(&current->mm->mmap_sem); // Acquire read lock. Why?
  return error;
}

1 ответ

Вы, вероятно, не можете делать то, что вы хотите (в пространстве пользователя, без взлома ядра). Обратите внимание, что запись нулевых страниц может не повлечь за собой физический дисковый ввод-вывод из-за кеша страниц.

Возможно, вы захотите заменить сегмент файла на дыру в файле (но это не совсем то, что вам нужно) в разреженном файле, но некоторые файловые системы (например, VFAT) не имеют дыр или разреженных файлов. Смотрите lseek(2) с SEEK_HOLE, ftruncate (2)

Другие вопросы по тегам