С чего всё началось
У меня 8 гигабайт оперативки. На бумаге звучит терпимо — ровно до того момента, пока не откроешь десятка два вкладок в хроме, рядом Figma, Slack, ещё вкладку со Stack Overflow, и поверх всего этого попробуешь что-то писать в VS Code. Сначала система начинает подтормаживать. Потом подтормаживать сильнее. В какой-то момент я просто встаю и иду за чаем — и, возвращаясь, нередко застаю её всё в той же задумчивости.
Логичное решение — докупить плашку. Но тут засада: один слот на плате занят, а второго… просто нет. Ноут. (Хотя, если честно, будь даже свободный слот — не факт, что прямо сейчас нашлись бы деньги на лишнюю плашку.)
И вот сижу я, смотрю в диспетчер задач: RAM забита под потолок, а видеокарта со своими 6 ГБ VRAM стоит в сторонке и в ус не дует. Никакой тяжёлой графики, просто простаивает.
Тут-то вопрос и нарисовался: а нельзя ли, хотя бы теоретически, приспособить видеопамять под расширение оперативки?
Почему «вместо RAM» — сразу не то слово
Оговорюсь заранее, иначе в комментариях прилетит «автор не понимает, о чём пишет».
К обычной RAM процессор обращается напрямую — через контроллер памяти, который сидит прямо на кристалле. Задержка — где-то 70 наносекунд. Это очень быстро.
VRAM физически живёт на видеокарте, по ту сторону шины PCIe. Чтобы дотянуться до байта в видеопамяти, процессору нужно собрать транзакцию, прогнать её через слот, дождаться, пока GPU ответит, и забрать данные назад. Это уже микросекунды, то есть на пару порядков медленнее.
Плюс туда не положишь таблицы страниц, и инструкции оттуда процессор с нормальной скоростью декодировать не умеет. Так что «использовать VRAM как RAM» в прямом смысле — нет, не выйдет.
Но рядом есть другая идея, и вот она вполне живая: сделать из VRAM очень быстрый своп.
Своп — штука, которая не раз спасала мне работу
Когда оперативка кончается, ОС не падает замертво. Она берёт страницы, к которым давно никто не обращался, и спихивает их куда-нибудь на диск. Это и есть своп, он же файл подкачки.
Обычно своп лежит на диске — HDD или SSD. Медленнее RAM, но несравнимо лучше, чем поймать out of memory и потерять несохранённое (привет всем, кто хоть раз так ронял полдня работы).
А что, если положить своп не на диск, а в VRAM?
Видеопамять — это, конечно, не DDR4. Но на последовательных операциях она ощутимо быстрее даже приличного NVMe. Очень грубо, по порядку величин:
|
Носитель |
Последовательное чтение |
Задержка |
|---|---|---|
|
DDR4 RAM |
~22 000 МБ/с |
~70 нс |
|
VRAM-своп (теоретически) |
~3 800 МБ/с |
~12 мкс |
|
Хороший NVMe |
~2 400 МБ/с |
~25 мкс |
|
SATA SSD |
~520 МБ/с |
~120 мкс |
Цифры тут заведомо прикидочные — надёргала из datasheet’ов и собственных старых замеров, так что относитесь к ним как к «плюс-минус», а не как к честному бенчмарку. Но даже так выходит, что VRAM-своп мог бы оказаться раз в 5–10 быстрее дискового. Для фоновых вкладок хрома, которые висят и просыпаются раз в полчаса, этого за глаза.
Как это можно было бы собрать
Вот тут начинается самое любопытное. ОС про VRAM ничего не знает — она умеет в блочные устройства: диски, флешки, разделы. Значит, нужно как-то прикинуться, что кусок видеопамяти — это блочное устройство.
Один из красивых вариантов — NBD. Протокол, в котором userspace-программа ловит команды «прочитай блок», «запиши блок», а внутри творит что хочет. Linux держит NBD из коробки, под Windows есть аналог — WNBD.
Картинка примерно такая:
Браузер, Figma, VS Code... ↕ (страницы памяти) Ядро ОС (своп / файл подкачки) ↕ (блочные операции) NBD / WNBD драйвер ↕ (TCP loopback) Наш гипотетический сервер (читает/пишет в VRAM через OpenCL) ↕ (PCIe) GPU
OpenCL тут — кросс-платформенный API к GPU: позволяет выделять буферы прямо в видеопамяти и читать-писать в них с хоста. Живёт на NVIDIA, AMD и Intel.
TCP loopback поначалу смущает — вроде лишний оверхед. Но на запросах от 4 КБ и выше он почти растворяется на фоне самой передачи по PCIe. Нормальный размен на простоту реализации.
Грабли, на которые стоит посмотреть заранее
Если вдруг кто-то решит это и правда собрать — есть несколько неочевидных мест.
VRAM волатильна, и в очень неприятном смысле. Обычная RAM теряет данные, только когда совсем выдёргиваешь питание. VRAM же может обнулиться при ресете драйвера (тот самый TDR — драйвер решил, что GPU завис, и передёрнул его), при подключении или отключении монитора, при уходе в сон. Для свопа это, в общем, переживаемо — он и так волатилен, ОС перечитает данные с диска. Но обычный дисковый своп держать про запас обязательно, иначе один сбой — и kernel panic.
Дедлок при высоком давлении на память. Самый коварный момент. Своп-сервер — это процесс. Когда памяти не хватает, ядро может захотеть выгрузить его собственные страницы. А куда выгружать? В своп. Который обслуживает этот самый процесс. Кольцо замкнулось, система висит. Лечится mlockall() в самом начале работы: все страницы процесса прибиваются к RAM, и ядро их больше не трогает. Без этого под нагрузкой всё встанет намертво.
GPU, который одновременно рисует и хранит своп. Если карта занята тяжёлой графикой, OpenCL-команды встают в очередь, своп подвисает, а за ним и приложения. Идея заметно лучше живёт на втором, дискретном GPU, который ничего не отображает. На ноуте с одной картой это риск, и принимать его надо осознанно.
Windows и pagefile на «съёмном» диске. Винда по умолчанию не даёт ставить файл подкачки на диски, которые считает removable. WNBD создаёт fixed-диски, так что обычно проблемы нет — но лучше проверить заранее, чем потом удивляться.
Hibernate с этой схемой не дружит. При гибернации Windows сбрасывает содержимое RAM в pagefile. Если pagefile живёт в VRAM, которая при выключении стирается, — содержимое уедет в никуда. Так что либо hibernate, либо VRAM-pagefile основным. Вместе — нет.
Что это дало бы лично мне
Я, мои 8 ГБ и хром на тридцать вкладок. Часть активна, часть — «вернусь попозже», а часть я уже и не помню, зачем открывала.
Если бы получилось отдать 4–6 ГБ VRAM под своп с высоким приоритетом, давно неактивные вкладки уезжали бы туда — быстро и незаметно. А при возврате поднимались бы из видеопамяти (по скорости примерно как с быстрого NVMe), а не перегружались из сети и не вытягивались мучительно с диска.
Сейчас переключение между задачами при нехватке памяти — это ожидание на 10–30 секунд. С VRAM-свопом, по прикидкам, секунды или доли. Разница, которую чувствуешь не в графиках, а прямо руками.
Что уже можно потрогать
Это, кстати, не чистая фантазия — кое-что придумано и до меня.
vramfs (2014) — FUSE-файловая система поверх OpenCL-буфера. Проект давно заброшен, на новых системах без напильника не заведётся, но сама концепция рабочая.
GpuRamDrive — готовое приложение под Windows: делает виртуальный диск в памяти GPU через CUDA и драйвер ImDisk. Только NVIDIA, зато компилировать ничего не надо, и pagefile на него ставится штатными средствами.
NBD + WNBD + OpenCL — сборка из открытых кусков своими руками. И Linux, и Windows, любые OpenCL-совместимые карты. Но придётся брать компилятор и разбираться.
Кому это вообще надо, а кому нет
По-честному, идея нишевая.
Есть смысл, если память распаяна и не расширяется, или если все слоты уже заняты; если есть дискретный GPU, который в твоём сценарии простаивает; и если краша по OOM не хочется, но и дёргать диск каждые пять секунд тоже не вариант.
Смысла нет, если GPU и так пашет под графику или ML; если можно просто докупить планку (тогда лучше так и сделать, серьёзно); или если нужна надёжность продакшен-уровня — для неё это всё несерьёзно.
И под конец…
Сама я это пока не собрала. Идея цепляет меня именно тем, что она про ресурс, который в некоторых сценариях реально валяется без дела. Шесть гигабайт на видяхе, пока ковыряешься в текстовом редакторе, а рядом хром душит систему, — это, согласитесь, немножко обидно.
Если кто-то уже игрался с GpuRamDrive или vramfs — расскажите, как оно на практике. И отдельно интересно: как такая схема ведёт себя под живой нагрузкой вкладками, а не в синтетике? У меня пока только теория и раздражение от диспетчера задач.
ссылка на оригинал статьи https://habr.com/ru/articles/1042028/