2014-01-27 3 views
3

У меня есть класс BitVector, который может либо распределять память динамически, используя new, либо файл mmap. Нет заметной разницы в производительности при использовании с небольшими файлами, но при использовании 16-гигабайтного файла я обнаружил, что файл mmap намного медленнее, чем память, выделенная new. (Что-то вроде 10x медленнее или более.) Обратите внимание, что у моей машины 64 ГБ ОЗУ.mmap в сравнении с памятью, выделенной новым

Этот код загружает значения из большого файла диска и помещает их в фильтр Bloom, который использует мой класс BitVector для хранения.

Сначала я подумал, что это может быть потому, что резервная копия для файла mmap была на том же диске, что и файл, с которого я загружался, но это, похоже, не было проблемой. Я поставил два файла на два физически разных диска, и никаких изменений в производительности не произошло. (Хотя я считаю, что они находятся на одном контроллере.)

Затем я использовал mlock, чтобы попытаться заставить все в ОЗУ, но реализация mmap все еще была очень медленной.

Итак, пока я просто выделяю память непосредственно. Единственное, что я изменяю в коде для этого сравнения, это флаг конструктора BitVector.

Обратите внимание, что для измерения производительности я смотрю на top и просматриваю, сколько состояний я могу добавить в цветной фильтр в секунду. Использование ЦП даже не регистрируется на top при использовании mmap - хотя jbd2/sda1-8 начинает двигаться вверх (я работаю на сервере Ubuntu), который выглядит как процесс, связанный с ведением журнала для диска. Файлы ввода и вывода хранятся на двух жестких дисках.

Может ли кто-нибудь объяснить эту огромную разницу в производительности?

Спасибо!

+0

AFAIK, политика по умолчанию ттара для чтения больших страниц разве довольно хорошо. Можете ли вы повторно запустить свой случай после установки флага MAP_POPULATE и использования madvise также с флагами MADV_SEQUENTIAL (если ваш доступ последователен) или MADV_RANDOM (если произвольный доступ) OR'ed с MADV_WILLNEED (чтобы предотвратить перезагрузку страниц). – Arunmu

+0

Это, безусловно, неожиданное поведение, в частности потому, что 'operator new' использует' malloc', который использует 'mmap' для больших запросов! Когда вы говорите «используя файл 16 ГБ», который предполагает, что вы используете файл _real_, а не один из '/ dev/shm'? Если это так, и, в частности, поскольку вы заметили, что процесс журналирования продолжается, замедление может быть связано с доступом к диску для чтения и при сбое (хотя я не знал, что ОС должна делать на диске для пустых нулевых страниц) , – Damon

+0

@Damon - Я использую настоящий файл, а не временный файл. Я обращаюсь к нему случайным образом, хотя, если его заблокировать в памяти, похоже, это не имеет значения. –

ответ

3

Для начала, mmap - это системный вызов или интерфейс, обеспечивающий доступ к виртуальной памяти системы.
Теперь в Linux (я надеюсь, что вы работаете на * NIX) много повышения производительности является дружнее по отложенной загрузки или более широко известный как Copy-On-Запись.

Для mmap также предусмотрена эта ленивая загрузка.

Что происходит, когда вы вызываете mmap в файл, ядро ​​не сразу выделяет страницы основной памяти для отображаемого файла.
Вместо этого он ожидает, что программа будет писать/читать с иллюстративной страницы, на какой стадии происходит ошибка ., и соответствующий обработчик прерывания фактически загрузит эту конкретную часть файла, которая может быть сохранена на этой странице frame (Также обновляется таблица страниц, поэтому в следующий раз, когда вы читаете/записываете на ту же страницу, она указывает на действительный фрейм).

Теперь вы можете контролировать это поведение с mlock, madvise, MAP_POPULATE флагом с ММАП и т.д.
MAP_POPULATE флаги с mmap, сообщает ядру, чтобы отображать файл на страницы памяти до того, как вызов возвращается, а не ошибка страницы при каждом доступе к новой странице. Таким образом, до загрузки файла функция будет заблокирована.

От Man Страницы:

 
MAP_POPULATE (since Linux 2.5.46) 
       Populate (prefault) page tables for a mapping. For a file 
       mapping, this causes read-ahead on the file. Later accesses 
       to the mapping will not be blocked by page faults. 
       MAP_POPULATE is supported for private mappings only since 
       Linux 2.6.23. 

Смежные вопросы