Обычно списки реализуются либо как связанные списки, которые медленно перемещаются, либо как списки массивов, которые медленны при вставке элементов.
Мне было интересно, можно ли будет использовать MMU процессора для более эффективной реализации списков, переназначая вместо копирования память всякий раз, когда элемент вставляется или удаляется. Это будет означать, что как индексирование, так и вставка / удаление в любом месте массива будут иметь скорость O (1), лучше, чем любая другая реализация списка.
Мои вопросы:
Сначала несколько конкретных ответов на ваши вопросы:
mmap
в UNIX-подобных ОС и похожие API на винде. Linux, в частности, недавно добавил несколько методы чтобы разрешить расширенные манипуляции с видимыми пользователем буферами из ядра без копирования — но один из интересных больше не для этого мира (по крайней мере, с точки зрения производительности). Основная проблема с использованием трюков MMU заключается в том, что (а) вы можете только «обнулить» целые страницы, что в значительной степени означает гранулярность 4К или более, наряду с аналогичным ограничительным выравниванием (б), даже если mmap
вызовы быстрого типа, так что эффективные процедуры копирования памяти!
Давайте сначала посмотрим на (а). Если я вас правильно понимаю, вы хотите ускорить вставку во что-то вроде std::vector
используя трюки MMU, чтобы сместить элементы, которые нужно переместить, когда происходит вставка. Проблема в том, что в типичных системах вы можете сдвигать байты только на 0, 4096, 8192 и т. Д.! Так что если вы вставите один 4-байтовый int
в vector<int>
как это поможет? Вы могли бы, возможно, «взломать» основное хранилище vector
разделить на две части в точке вставки и отследить это с надеждой объединить их снова в какой-то момент (например, если вы вставите вещи размером 4096 байт) — но в итоге вы получите другую структуру данных, с другими свойствами и трюками MMU во всяком случае, здесь не очень важно.
Это подводит нас к (б). Примите как должное, что на моей машине страница может быть переназначена в ~ 120 нс (через mmap
). Это кажется быстрым (это неплохо, если учесть, что нужно использовать различные блокировки ядра, возиться с таблицами страниц, добавлять VMA и т. Д.), Но копирование памяти также очень быстро. На этом же ящике я могу копировать в оперативной памяти (т.е. в / из ОЗУ любого уровня кэша) со скоростью около 12 ГБ / с, в то время как копии в L1 или L2 продолжаются со скоростью, вероятно, 80–100 ГБ / с. Таким образом, копирование страницы 4K занимает где-то между 41 нс (кэшировано) и 340 нс (не кэшировано, в ОЗУ). Так что возиться с таблицами страниц не является очевидной победой, даже если бы возможный, особенно в кэшированном случае (и кэшированный случай, вероятно, является доминирующим, усредненным по большинству рабочих нагрузок).
Так что эти типы трюков может имеет смысл, но только в определенных сценариях, таких как следующие:
Самый распространенный и полезный пример MMU хитрости возможно realloc
, В Linux и Windows (похоже на то?), realloc
может быть реализовано путем переназначения и расширения отображаемых страниц в памяти (т. е. трюки MMU), что позволяет избежать физического копирования и необходимости временного одновременного «живого» старого выделенного региона и нового региона (что может быть трудно, если их сумма приближается к размеру физической памяти).
В частности, последняя версия Linux, вероятно, будет использовать mremap
в realloc
куча регионов, которые были mmap
в первую очередь (по умолчанию это происходит для запросов на выделение размером более 128 КБ, но также может происходить, когда пространство доступно для sbrk
исчерпан).
Других решений пока нет …