Использование MMU для реализации массивов с изменяемым размером

Обычно списки реализуются либо как связанные списки, которые медленнее перемещаются, либо как списки массивов, которые медленны при вставке элементов.

Мне было интересно, можно ли использовать MMU процессора для более эффективной реализации списков путем переназначения вместо копирования памяти всякий раз, когда элемент вставляется или удаляется. Это будет означать, что и индексация, и вставка/удаление в любом месте массива будут иметь скорость O(1), лучше, чем любые другие реализация списка.

Мои вопросы:

  • Действительно ли программы могут управлять своей собственной виртуальной памятью или необходимо внести изменения в ОС?
  • Есть ли ограничение на количество записей в таблице страниц на процесс? Становится ли доступ к памяти медленнее с увеличением количества записей?
  • Является ли изменение записей таблицы страниц настолько медленным, что это было бы более эффективно только для очень больших списков?
  • Существуют ли какие-либо существующие реализации этого типа списка? Если да, то что мешает людям использовать их больше?

person d9584    schedule 06.01.2017    source источник
comment
См. в качестве хорошей точки входа эту ссылку: msdn.microsoft.com/en-us/library/windows/desktop/ Суть в том, что управление виртуальной памятью может контролироваться приложениями. Но страницы, которые раздаются, не имеют произвольного размера. Итак, если вы хотите воплотить свою идею в жизнь, попробуйте. Но вы потратите много (виртуальной) памяти, если ваши элементы списка меньше размеров страницы... В любом случае, я сомневаюсь, что вы получите что-то полезное/работающее. Но респект за творческий дух!   -  person BitTickler    schedule 06.01.2017
comment
Большинство современных процессоров используют умеренные, но существенные размеры страниц. 4kb и 8kb типичны. MMU можно использовать только для отображения фрагментов памяти, которые кратны размеру страницы. Если ваши объекты не имеют точного выравнивания и их размер не кратен размеру страницы, MMU бесполезен. И даже если эта утка выстроилась в ряд: удачи в написании собственной операционной системы!   -  person Sam Varshavchik    schedule 06.01.2017
comment
Если вас интересуют новейшие и лучшие современные структуры данных: Найдите постоянные структуры данных. Идеи исходят из функционального программирования, но также могут быть полезны в C++/Rust или системном коде.   -  person BitTickler    schedule 06.01.2017
comment
uic.pure. elsevier.com/en/publications/   -  person    schedule 06.01.2017
comment
@SamVarshavchik - даже если объекты намного меньше размера страницы, приемы MMU в принципе могут быть полезны - например, объединение двух больших буферов или трюк с круговым буфером Я дал ссылку в своем ответе. Наиболее известным примером трюка с MMU на самом деле является realloc, который для больших распределений использует MMU, чтобы эффективно разрешить расширение выделенной области без фактического копирования базовых элементов.   -  person BeeOnRope    schedule 06.01.2017
comment
Вы не должны слишком серьезно относиться к нотации O(). Разница между $O(1)$ и $O(\log n)$ может быть меньше, чем разница в мультипликативной константе для любого разумного $n$. Использование MMU означает обращение к ОС, что требует больших затрат.   -  person Stig Hemmer    schedule 06.01.2017
comment
@StigHemmer - да, хотя в некоторых ОС стоимость на самом деле не так уж и высока, и эта техника заслуживает внимания. В Linux, например, стоимость составляет несколько 100 нс за вызов плюс около 100 нс за отображаемую страницу размером 4 КБ. Таким образом, 100 нс для обработки страницы размером 4 КБ соответствует примерно 25 ГБ/с, что, как правило, немного выше, чем может достичь подпрограмма memcpy, и дополнительно использует в основном ресурсы ЦП, а не общую (с другими ядрами) шину DRAM. Конечно, у него есть и другие недостатки. Это со страницами 4K — если вы используете страницы размером 2 МБ, вы сокращаете необходимые манипуляции в 500 раз.   -  person BeeOnRope    schedule 25.01.2017


Ответы (1)


Сначала несколько конкретных ответов на ваши вопросы:

  • Да, во многих ОС программы имеют значительный контроль над своей виртуальной памятью, например, mmap в UNIX-подобных ОС и аналогичные API в Windows. В частности, Linux недавно добавил несколько методы, позволяющие расширенные манипуляции с видимыми пользователю буферами из ядра без копирования только одного из интересных — больше не для этого мира (по крайней мере, с точки зрения производительности).
  • Обычно не существует конкретных ограничений на количество записей в таблице страниц для каждого процесса. Конечно, вы можете столкнуться с другими ограничениями, такими как ограничения памяти для каждого процесса, ограничения физической памяти и так далее. Доступ к памяти обычно не замедляется при увеличении количества записей. Конечно, общий доступ к большему количеству страниц может означать более медленный доступ (например, из-за превышения размера TLB), но это не является прямой функцией большего количества страниц. Сами записи таблицы страниц просто находятся в ОЗУ, поэтому вы можете без проблем иметь их миллионы.
  • Изменение записей в таблице страниц выполняется достаточно быстро в современных операционных системах. Например, на моем ноутбуке изменение записей в таблице страниц занимает около 120 нс на страницу (плюс некоторые фиксированные накладные расходы на системный вызов).
  • Да, вы можете найти примеры, но они обычно нацелены на довольно узкие сценарии. Фактически, вы можете видеть, что libc mach пытается использовать use Трюки MMU для не менее важной процедуры чем memcpy !

Обсуждение

Основная проблема с использованием трюков MMU заключается в том, что (а) вы можете «нулевое копирование» только целых страниц, что в значительной степени означает гранулярность 4 КБ или больше, наряду с аналогичным ограничительным выравниванием (б) даже если вызовы типа mmap выполняются быстро, как и эффективные процедуры копирования памяти!

Сначала рассмотрим (а). Если я вас правильно понял, вы хотите ускорить вставку во что-то вроде std::vector, используя приемы MMU для смещения элементов, которые необходимо переместить, когда происходит вставка. Проблема в том, что вы можете сдвигать только на 0, 4096, 8192 и т. д. байт на обычных системах! Итак, если вы вставите один 4-байтовый int в vector<int>, как это поможет? Возможно, вы могли бы «разбить» базовое хранилище vector на две части в точке вставки и отследить это с надеждой снова объединить их в какой-то момент (например, если вы вставите материал размером 4096 байт) - но вы в конечном итоге с другая структура данных, с другими свойствами, и трюки с MMU в любом случае не являются здесь фундаментальными.

Это подводит нас к пункту (б). Примите как должное, что на моей машине страница может быть переназначена примерно за 120 нс (через mmap). Это кажется быстрым (это неплохо, если учесть, что это включает в себя различные блокировки ядра, возню с таблицами страниц, добавление VMA и т. д.), но копирование памяти также происходит очень быстро. На этом же компьютере я могу копировать в память (то есть в/из ОЗУ любого уровня кэша) со скоростью около 12 ГБ/с, в то время как копирование в L1 или L2 происходит со скоростью 80-100 ГБ/с. Таким образом, копирование страницы размером 4 КБ занимает где-то между 41 нс (кэширование) и 340 нс (некэширование, в ОЗУ). Таким образом, возня с таблицами страниц не является явным выигрышем, даже если это было бы возможно, особенно в случае с кэшированием (а случай с кэшированием, вероятно, является доминирующим, усредняющим большинство рабочих нагрузок).

Таким образом, эти типы приемов могут иметь смысл, но только в определенных сценариях, таких как следующие:

  • У вас есть какой-то способ справиться с тем фактом, что сопоставление страниц может перемещать/копировать/перемещать элементы только в фрагментах детализации страницы, например, потому что ваши структуры кратны детализации страницы, или вы используете пакетные вставки, которые являются кратными детализации страниц и т. д.
  • У вас есть способ более быстрого сопоставления страниц: например, используя страницы размером 2 МБ, а не страницы размером 4 КБ, или написав некоторый код на стороне ядра, который ускоряет ваш вариант использования.
  • Вы хотите использовать даже более причудливые приемы, чем просто перемещение памяти, например. заставить одни и те же данные появляться в двух местах одновременно, реализовать структуры COW или что-то в этом роде.

Реаллок

Самый распространенный и полезный пример трюков MMU — это, вероятно, realloc. В Linux и Windows (это кажется?), realloc можно реализовать путем переназначения и расширения отображаемых страниц в памяти (так называемые приемы MMU), что позволяет избежать физической копии и необходимости временно иметь как старую выделенную область, так и новую область «живыми». " сразу (что может быть сложно, если их сумма приближается к размеру физической памяти).

В частности, последняя версия Linux, скорее всего, будет использовать mremap для realloc областей кучи, которые были mmaped в первую очередь (по умолчанию это происходит для запросов на выделение больше 128 КБ, но это также может произойти, когда пространство, доступное для sbrk, исчерпано).

person BeeOnRope    schedule 06.01.2017
comment
Возможно, в сочетании с постоянными структурами данных все это действительно может быть хорошей идеей. Не для управления отдельными элементами массива, а для управления фрагментами... en.wikipedia.org/wiki/Persistent_data_structure< /а> - person BitTickler; 06.01.2017
comment
Кроме того, аннулирование TLB может быть еще медленнее на многопроцессорных машинах и многопоточных приложениях. - person Non-maskable Interrupt; 06.01.2017
comment
@BitTickler - наверняка: возможные логические операции копирования, которые происходят в постоянных структурах, и необходимость перехватывать записи, если вы хотите выполнить какой-либо тип COW, оба потенциально хорошо подходят для помощи MMU. Конечно, большие деньги делаются на деталях, и есть много препятствий, которые необходимо преодолеть (например, перехват операций записи и их эффективное сопоставление с пользовательской структурой в многопоточной среде и т. д.). - person BeeOnRope; 06.01.2017
comment
@Non-maskableInterrupt - в принципе да. Имейте в виду, что mmap обычно не делает TLB недействительным, так как это только добавление записей в таблицу страниц процесса, а не их удаление (и я не знаю ни одного современного TLB, в котором хранятся отрицательные значения). записи). С другой стороны, munmap или mremap обычно включают некоторый тип сброса TLB, в том числе кросс-процессорные перестрелки, если приложение. Тем не менее, в моих тестах я измерил, что munmap составляет лишь половину стоимости mmap, даже с предполагаемыми промахами TLB. - person BeeOnRope; 06.01.2017