Как управляется память CUDA? - PullRequest
       34

Как управляется память CUDA?

24 голосов
/ 31 декабря 2011

Когда я запускаю свою программу CUDA, которая выделяет только небольшой объем глобальной памяти (ниже 20 М), я получаю ошибку «недостаточно памяти». (Из постов других людей, я думаю, что проблема связана с фрагментацией памяти) Я пытаюсь понять эту проблему и понимаю, что у меня есть пара вопросов, связанных с управлением памятью CUDA.

  1. Существует ли концепция виртуальной памяти в CUDA?

  2. Если на CUDA разрешено одновременно работать только одному ядру, после его завершения будет ли освобождена вся используемая или выделенная память? Если нет, то когда освободится эта память?

  3. Если в CUDA разрешено запускать несколько ядер, как они могут убедиться, что используемая ими память не перекрывается?

Может кто-нибудь помочь мне ответить на эти вопросы? Спасибо

Редактировать 1: операционная система: x86_64 GNU / Linux Версия CUDA: 4.0 Устройство: Geforce 200, это один из GPUS, подключенных к машине, и я не думаю, что это устройство отображения.

Редактировать 2: Вот что я получил после некоторых исследований. Не стесняйтесь поправлять меня.

  1. CUDA создаст один контекст для каждого потока хоста. В этом контексте будет храниться информация, например, какая часть памяти (предварительно выделенная память или динамически выделенная память) была зарезервирована для этого приложения, чтобы другое приложение не могло выполнить запись в нее. Когда это приложение завершает работу (не ядро), эта часть памяти будет освобождена.

  2. Память CUDA поддерживается списком ссылок. Когда приложению необходимо выделить память, оно будет проходить через этот список ссылок, чтобы увидеть, есть ли непрерывный кусок памяти, доступный для выделения. Если не удается найти такой блок, об ошибке «недостаточно памяти» будет сообщено пользователям, даже если общий объем доступной памяти больше, чем запрошенная память. И это проблема, связанная с фрагментацией памяти.

  3. cuMemGetInfo сообщит вам, сколько памяти свободно, но не обязательно, сколько памяти вы можете выделить при максимальном выделении из-за фрагментации памяти.

  4. На платформе Vista (WDDM) возможна виртуализация памяти графического процессора. То есть несколько приложений могут выделить почти всю память графического процессора, а WDDM будет управлять обменом данными обратно в основную память.

Новые вопросы: 1. Если память, зарезервированная в контексте, будет полностью освобождена после завершения работы приложения, фрагментации памяти не должно быть. В памяти должны быть какие-то данные. 2. Есть ли способ реструктурировать память GPU?

Ответы [ 2 ]

25 голосов
/ 31 декабря 2011

Память устройства, доступная вашему коду во время выполнения, в основном рассчитывается как

Free memory =   total memory 
              - display driver reservations 
              - CUDA driver reservations
              - CUDA context static allocations (local memory, constant memory, device code)
              - CUDA context runtime heap (in kernel allocations, recursive call stack, printf buffer, only on Fermi and newer GPUs)
              - CUDA context user allocations (global memory, textures)

если вы получаете сообщение о нехватке памяти, вполне вероятно, что один или несколько из первых трех элементов потребляют большую часть памяти графического процессора, прежде чем ваш пользовательский код попытается получить память в графическом процессоре. Если, как вы указали, вы не работаете на графическом процессоре, то статическое распределение контекста является наиболее вероятным источником вашей проблемы. CUDA работает, предварительно выделяя всю память, которая требуется контексту во время установления контекста на устройстве. Есть много вещей, которые выделяются для поддержки контекста, но самый большой потребитель в контексте - это локальная память. Среда выполнения должна зарезервировать максимальный объем локальной памяти, который будет использоваться любым ядром в контексте, для максимального количества потоков, которые каждый мультипроцессор может запустить одновременно, для каждого многопроцессорного устройства. Это может привести к сотням Мб памяти, если на устройстве с большим количеством многопроцессорных систем загружено тяжелое ядро ​​локальной памяти.

Лучший способ увидеть, что может происходить, - это написать хост-программу без кода устройства, который устанавливает контекст и вызывает cudaMemGetInfo. Это покажет вам, сколько памяти имеет устройство с минимальными затратами контекста на нем. Затем запустите проблемный код, добавив тот же вызов cudaMemGetInfo перед первым вызовом cudaMalloc, который даст вам объем памяти, используемый вашим контекстом. Это может позволить вам получить представление о том, куда идет память. Маловероятно, что фрагментация является проблемой, если вы получаете сбой при первом вызове cudaMalloc.

4 голосов
/ 31 декабря 2011
  1. Внешняя память GPU разделена на глобальную, локальную и постоянную память.Эти три типа памяти являются концепцией виртуальной памяти.Глобальная память свободна для всех потоков, локальная - только для одного потока (в основном используется для пролива регистров), а постоянная память - в кешируемой глобальной памяти (доступная для записи только из кода хоста).Взгляните на 5.3.2 из Руководства по программированию CUDA C.

  2. РЕДАКТИРОВАТЬ: удалено

  3. Память, выделенная через cudaMalloc, никогда не перекрывается,Для памяти, выделяемой ядром во время выполнения, должно быть достаточно доступной памяти.Если у вас недостаточно памяти и вы пытаетесь запустить ядро ​​(только предположение от меня), вы должны получить сообщение об ошибке «неизвестная ошибка».Драйвер, который не смог запустить и / или выполняет ядро.

...