Проблема
Пытаясь уменьшить / исключить возникновение незначительных ошибок страниц в приложении, я обнаружил сбивающий с толку феномен; а именно, я неоднократно вызываю незначительные ошибки страниц для записи на один и тот же адрес, хотя я думал, что предпринял достаточные шаги для предотвращения ошибок страниц.
Задний план
Согласно совету, здесь, я вызвал mlockall
, чтобы заблокировать все текущие и будущие страницы в памяти.
В моем первоначальном варианте использования (который включал довольно большой массив) я также предварительно обработал данные, записав их в каждый элемент (или, по крайней мере, на каждую страницу) в соответствии с советом здесь; хотя я понимаю, что этот совет предназначен для пользователей, использующих ядро с исправлением RT, общая идея принудительной записи для предотвращения подкачки COW / запроса должна оставаться применимой.
Я думал, что mlockall
можно использовать для предотвращения мелких ошибок страницы. В то время как страница руководства только кажется, гарантирует, что не будет никаких серьезных ошибок, различные другие ресурсы (например, выше) заявляют, что ее также можно использовать для предотвращения незначительных ошибок страницы.
Документация к ядру, кажется, тоже указывает на это. Например, unevictable-lru.txt и pagemap.txt заявляют, что mlock()
' ed страницы невозможно удалить, и поэтому они не подходят для повторного использования.
Несмотря на это, я продолжал вызывать несколько мелких ошибок страниц.
Пример
Я создал чрезвычайно урезанный пример, чтобы проиллюстрировать проблему:
#include <sys/mman.h> // mlockall
#include <stdlib.h> // abort
int main(int , char **) {
int x;
if (mlockall(MCL_CURRENT | MCL_FUTURE)) abort();
while (true) {
asm volatile("" ::: "memory"); // So GCC won't optimize out the write
x = 0x42;
}
return 0;
}
Здесь я неоднократно пишу по одному и тому же адресу. Легко увидеть (например, через cat /proc/[pid]/status | awk '{print $10}'
), что у меня по-прежнему возникают незначительные ошибки страниц после завершения инициализации.
Запуская модифицированную версию * сценария pfaults.stp
, включенного в systemtap-doc
, я регистрировал время каждой ошибки страницы, адрес, вызвавший ошибку, адрес инструкции, которая вызвала ошибку, была ли она основной / второстепенной, а также чтение / запись. После начальных ошибок при запуске и mlockall
все ошибки были идентичны: попытка записи в x
вызвала незначительную ошибку записи.
Интервал между последовательными ошибками страниц демонстрирует поразительную картину. Для одного конкретного прогона интервалы были в секундах: 2, 4, 4, 4.8, 8.16, 13.87, 23.588, 40.104, 60, 60, 60, 60, 60, 60, 60, 60, 60, ...
Это выглядит (приблизительно) экспоненциальным откатом с абсолютным потолком в 1 минуту.
Запуск его на изолированном процессоре не оказывает никакого влияния; также не выполняется работа с более высоким приоритетом. Однако работа с приоритетом в реальном времени устраняет ошибки страниц.
Вопросы
- Ожидается ли такое поведение?
1a. Что объясняет время? - Можно ли это предотвратить?
Версии
Я использую Ubuntu 14.04 с ядром 3.13.0-24-generic
и версией Systemtap 2.3/0.156, Debian version 2.3-1ubuntu1 (trusty)
. Код, скомпилированный с gcc-4.8
, без дополнительных флагов, хотя уровень оптимизации, похоже, не имеет значения (при условии, что директива asm volatile
остается на месте; в противном случае запись полностью оптимизируется)
Я буду рад включить дополнительные сведения (например, точный сценарий stap
, исходный результат и т. Д.), Если они окажутся актуальными.
* На самом деле, зонд vm.pagefault
был сломан для моей комбинации ядра и systemtap, потому что он ссылался на переменную, которой больше не существовало в функции ядра handle_mm_fault
, но исправление было тривиальным)