Подтвердить что ты не робот

Можно ли получить доступ к жесткому диску непосредственно из gpu?

Можно ли получить доступ к жесткому диску/флеш-памяти непосредственно с GPU (CUDA/openCL) и загрузить/сохранить контент непосредственно из памяти GPU?

Я пытаюсь избежать копирования файлов с диска в память и затем скопировать его в память GPU.

Я читал о Nvidia GPUDirect, но не уверен, что он делает то, что я объяснил выше. В нем рассказывается о удаленной памяти и дисках GPU, но диски в моем случае являются локальными для GPU.

Основная идея - загрузить содержимое (что-то вроде dma) → выполнить некоторые операции → сохранить содержимое обратно на диск (снова в режиме dma).

Я пытаюсь задействовать CPU и RAM как можно меньше здесь.

Пожалуйста, не стесняйтесь предлагать какие-либо предложения по дизайну.

4b9b3361

Ответ 1

Для всех, кто ищет это, "ленивый отказ" сделал более или менее то, что я хочу.

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

Наиболее простая реализация, использующая RDMA для GPUDirect, памяти перед каждой передачей и отключить ее сразу после передачи завершено. К сожалению, это будет плохо работать в целом, поскольку пиннинг и открепление памяти - это дорогостоящие операции. Остаток от однако шаги, необходимые для выполнения передачи RDMA, могут выполняться быстро без ввода ядра (список DMA можно кэшировать и воспроизводится с использованием регистров MMIO/списков команд).

Следовательно, лениво неокрашиваемая память является ключом к высокопроизводительной RDMA реализация. То, что это подразумевает, удерживает память, закрепленную даже после завершения передачи. Это использует тот факт, что вполне вероятно, что одна и та же область памяти будет использоваться для будущего DMA поэтому lazy unpinning сохраняет операции pin/unpin.

Пример реализации ленивого отказа будет содержать набор закрепленных областей памяти и только некоторые из них (например, наименее недавно использовали один), если общий размер регионов достиг некоторого пороговое значение, или если сбой в новой области не удался из-за пространства BAR (см. размеры PCI BAR).

Вот ссылка на руководство по применению и nvidia документы.

Ответ 2

Пытаясь использовать эту функцию, я написал небольшой пример для Windows x64, чтобы реализовать это. В этом примере ядро ​​ "напрямую" обращается к дисковым пространствам. На самом деле, как упоминал ранее @RobertCrovella, операционная система выполняет свою работу, возможно, с некоторой работой процессора; но никакого дополнительного кодирования.

__global__ void kernel(int4* ptr)
{
    int4 val ; val.x = threadIdx.x ; val.y = blockDim.x ; val.z = blockIdx.x ; val.w = gridDim.x ;
    ptr[threadIdx.x + blockDim.x * blockIdx.x] = val ;
    ptr[160*1024*1024 + threadIdx.x + blockDim.x * blockIdx.x] = val ;
}

#include "Windows.h"

int main()
{
    // 4GB - larger than installed GPU memory
    size_t size = 256 * 1024 * 1024 * sizeof(int4) ;

    HANDLE hFile = ::CreateFile ("GPU.dump", (GENERIC_READ | GENERIC_WRITE), 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) ;

    HANDLE hFileMapping = ::CreateFileMapping (hFile, 0, PAGE_READWRITE, (size >> 32), (int)size, 0) ;

    void* ptr = ::MapViewOfFile (hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, size) ;

    ::cudaSetDeviceFlags (cudaDeviceMapHost) ;

    cudaError_t er = ::cudaHostRegister (ptr, size, cudaHostRegisterMapped) ;
    if (cudaSuccess != er)
    {
        printf ("could not register\n") ;
        return 1 ;
    }

    void* d_ptr ;
    er = ::cudaHostGetDevicePointer (&d_ptr, ptr, 0) ;
    if (cudaSuccess != er)
    {
        printf ("could not get device pointer\n") ;
        return 1 ;
    }

    kernel<<<256,256>>> ((int4*)d_ptr) ;

    if (cudaSuccess != ::cudaDeviceSynchronize())
    {
        printf ("error in kernel\n") ;
        return 1 ;
    }

    if (cudaSuccess != ::cudaHostUnregister (ptr))
    {
        printf ("could not unregister\n") ;
        return 1 ;
    }

    ::UnmapViewOfFile (ptr) ;

    ::CloseHandle (hFileMapping) ;
    ::CloseHandle (hFile) ; 

    ::cudaDeviceReset() ;

    printf ("DONE\n");

    return 0 ;
}