国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

如何在CUDA中使用驅動程序API

星星科技指導員 ? 來源:NVIDIA ? 作者:Ken He ? 2022-05-07 15:07 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

驅動程序 API 在 cuda 動態庫(cuda.dll或cuda.so)中實現,該庫在安裝設備驅動程序期間復制到系統上。 它的所有入口點都以 cu 為前綴。

它是一個基于句柄的命令式 API:大多數對象都由不透明的句柄引用,這些句柄可以指定給函數來操作對象。

驅動程序 API 中可用的對象匯總在下表中。Table 16. Objects Available in the CUDA Driver API

pYYBAGJ2GteAcMJDAABKIgowDRk296.png

在調用驅動程序 API 的任何函數之前,必須使用cuInit()初始化驅動程序 API。 然后必須創建一個附加到特定設備的 CUDA 上下文,并使其成為當前調用主機線程,如上下文中所述。

在 CUDA 上下文中,內核作為 PTX 或二進制對象由主機代碼顯式加載,如模塊中所述。 因此,用 C++ 編寫的內核必須單獨編譯成 PTX 或二進制對象。 內核使用 API 入口點啟動,如內核執行中所述。

任何想要在未來設備架構上運行的應用程序都必須加載 PTX,而不是二進制代碼。 這是因為二進制代碼是特定于體系結構的,因此與未來的體系結構不兼容,而 PTX 代碼在加載時由設備驅動程序編譯為二進制代碼。

以下是使用驅動程序 API 編寫的內核示例的主機代碼:

int main()
{
    int N = ...;
    size_t size = N * sizeof(float);

    // Allocate input vectors h_A and h_B in host memory
    float* h_A = (float*)malloc(size);
    float* h_B = (float*)malloc(size);

    // Initialize input vectors
    ...

    // Initialize
    cuInit(0);

    // Get number of devices supporting CUDA
    int deviceCount = 0;
    cuDeviceGetCount(&deviceCount);
    if (deviceCount == 0) {
        printf("There is no device supporting CUDA.\n");
        exit (0);
    }

    // Get handle for device 0
    CUdevice cuDevice;
    cuDeviceGet(&cuDevice, 0);

    // Create context
    CUcontext cuContext;
    cuCtxCreate(&cuContext, 0, cuDevice);

    // Create module from binary file
    CUmodule cuModule;
    cuModuleLoad(&cuModule, "VecAdd.ptx");

    // Allocate vectors in device memory
    CUdeviceptr d_A;
    cuMemAlloc(&d_A, size);
    CUdeviceptr d_B;
    cuMemAlloc(&d_B, size);
    CUdeviceptr d_C;
    cuMemAlloc(&d_C, size);

    // Copy vectors from host memory to device memory
    cuMemcpyHtoD(d_A, h_A, size);
    cuMemcpyHtoD(d_B, h_B, size);

    // Get function handle from module
    CUfunction vecAdd;
    cuModuleGetFunction(&vecAdd, cuModule, "VecAdd");

    // Invoke kernel
    int threadsPerBlock = 256;
    int blocksPerGrid =
            (N + threadsPerBlock - 1) / threadsPerBlock;
    void* args[] = { &d_A, &d_B, &d_C, &N };
    cuLaunchKernel(vecAdd,
                   blocksPerGrid, 1, 1, threadsPerBlock, 1, 1,
                   0, 0, args, 0);

    ...
}

完整的代碼可以在 vectorAddDrv CUDA 示例中找到。

L.1. Context

CUDA 上下文類似于 CPU 進程。驅動 API 中執行的所有資源和操作都封裝在 CUDA 上下文中,當上下文被銷毀時,系統會自動清理這些資源。除了模塊和紋理或表面引用等對象外,每個上下文都有自己獨特的地址空間。因此,來自不同上下文的 CUdeviceptr 值引用不同的內存位置。

主機線程一次可能只有一個設備上下文當前。當使用 cuCtxCreate() 創建上下文時,它對調用主機線程是當前的。如果有效上下文不是線程當前的,則在上下文中操作的 CUDA 函數(大多數不涉及設備枚舉或上下文管理的函數)將返回 CUDA_ERROR_INVALID_CONTEXT。

每個主機線程都有一堆當前上下文。 cuCtxCreate() 將新上下文推送到堆棧頂部??梢哉{用 cuCtxPopCurrent() 將上下文與主機線程分離。然后上下文是“浮動的”,并且可以作為任何主機線程的當前上下文推送。 cuCtxPopCurrent() 還會恢復先前的當前上下文(如果有)。

還為每個上下文維護使用計數。 cuCtxCreate() 創建使用計數為 1 的上下文。cuCtxAttach() 增加使用計數,而 cuCtxDetach() 減少使用計數。當調用 cuCtxDetach() 或 cuCtxDestroy() 時使用計數變為 0,上下文將被銷毀。

驅動程序 API 可與運行時互操作,并且可以通過 cuDevicePrimaryCtxRetain() 從驅動程序 API 訪問由運行時管理的主上下文(參見初始化)。

使用計數有助于在相同上下文中運行的第三方編寫的代碼之間的互操作性。例如,如果加載三個庫以使用相同的上下文,則每個庫將調用 cuCtxAttach() 來增加使用計數,并在庫使用上下文完成時調用 cuCtxDetach() 來減少使用計數。對于大多數庫,預計應用程序會在加載或初始化庫之前創建上下文;這樣,應用程序可以使用自己的啟發式方法創建上下文,并且庫只需對傳遞給它的上下文進行操作。希望創建自己的上下文的庫(可能會或可能沒有創建自己的上下文的 API 客戶端不知道)將使用 cuCtxPushCurrent() 和 cuCtxPopCurrent(),如下圖所示。

L.2. Module

模塊是設備代碼和數據的動態可加載包,類似于 Windows 中的 DLL,由 nvcc 輸出(請參閱使用 NVCC 編譯)。 所有符號的名稱,包括函數、全局變量和紋理或表面引用,都在模塊范圍內維護,以便獨立第三方編寫的模塊可以在相同的 CUDA 上下文中互操作。

此代碼示例加載一個模塊并檢索某個內核的句柄:

CUmodule cuModule;
cuModuleLoad(&cuModule, "myModule.ptx");
CUfunction myKernel;
cuModuleGetFunction(&myKernel, cuModule, "MyKernel");

此代碼示例從 PTX 代碼編譯和加載新模塊并解析編譯錯誤:

#define BUFFER_SIZE 8192
CUmodule cuModule;
CUjit_option options[3];
void* values[3];
char* PTXCode = "some PTX code";
char error_log[BUFFER_SIZE];
int err;
options[0] = CU_JIT_ERROR_LOG_BUFFER;
values[0]  = (void*)error_log;
options[1] = CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES;
values[1]  = (void*)BUFFER_SIZE;
options[2] = CU_JIT_TARGET_FROM_CUCONTEXT;
values[2]  = 0;
err = cuModuleLoadDataEx(&cuModule, PTXCode, 3, options, values);
if (err != CUDA_SUCCESS)
    printf("Link error:\n%s\n", error_log);

此代碼示例從多個 PTX 代碼編譯、鏈接和加載新模塊,并解析鏈接和編譯錯誤:

#define BUFFER_SIZE 8192
CUmodule cuModule;
CUjit_option options[6];
void* values[6];
float walltime;
char error_log[BUFFER_SIZE], info_log[BUFFER_SIZE];
char* PTXCode0 = "some PTX code";
char* PTXCode1 = "some other PTX code";
CUlinkState linkState;
int err;
void* cubin;
size_t cubinSize;
options[0] = CU_JIT_WALL_TIME;
values[0] = (void*)&walltime;
options[1] = CU_JIT_INFO_LOG_BUFFER;
values[1] = (void*)info_log;
options[2] = CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES;
values[2] = (void*)BUFFER_SIZE;
options[3] = CU_JIT_ERROR_LOG_BUFFER;
values[3] = (void*)error_log;
options[4] = CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES;
values[4] = (void*)BUFFER_SIZE;
options[5] = CU_JIT_LOG_VERBOSE;
values[5] = (void*)1;
cuLinkCreate(6, options, values, &linkState);
err = cuLinkAddData(linkState, CU_JIT_INPUT_PTX,
                    (void*)PTXCode0, strlen(PTXCode0) + 1, 0, 0, 0, 0);
if (err != CUDA_SUCCESS)
    printf("Link error:\n%s\n", error_log);
err = cuLinkAddData(linkState, CU_JIT_INPUT_PTX,
                    (void*)PTXCode1, strlen(PTXCode1) + 1, 0, 0, 0, 0);
if (err != CUDA_SUCCESS)
    printf("Link error:\n%s\n", error_log);
cuLinkComplete(linkState, &cubin, &cubinSize);
printf("Link completed in %fms. Linker Output:\n%s\n", walltime, info_log);
cuModuleLoadData(cuModule, cubin);
cuLinkDestroy(linkState);

完整的代碼可以在 ptxjit CUDA 示例中找到。

L.3. Kernel Execution

cuLaunchKernel() 啟動具有給定執行配置的內核。

參數可以作為指針數組(在 cuLaunchKernel() 的最后一個參數旁邊)傳遞,其中第 n 個指針對應于第 n 個參數并指向從中復制參數的內存區域,或者作為額外選項之一( cuLaunchKernel()) 的最后一個參數。

當參數作為額外選項(CU_LAUNCH_PARAM_BUFFER_POINTER 選項)傳遞時,它們作為指向單個緩沖區的指針傳遞,在該緩沖區中,通過匹配設備代碼中每個參數類型的對齊要求,參數被假定為彼此正確偏移。

表 4 列出了內置向量類型的設備代碼中的對齊要求。對于所有其他基本類型,設備代碼中的對齊要求與主機代碼中的對齊要求相匹配,因此可以使用 __alignof() 獲得。唯一的例外是當宿主編譯器在一個字邊界而不是兩個字邊界上對齊 double 和 long long(在 64 位系統上為 long)(例如,使用 gcc 的編譯標志 -mno-align-double ) 因為在設備代碼中,這些類型總是在兩個字的邊界上對齊。

CUdeviceptr是一個整數,但是代表一個指針,所以它的對齊要求是__alignof(void*)。

以下代碼示例使用宏 (ALIGN_UP()) 調整每個參數的偏移量以滿足其對齊要求,并使用另一個宏 (ADD_TO_PARAM_BUFFER()) 將每個參數添加到傳遞給 CU_LAUNCH_PARAM_BUFFER_POINTER 選項的參數緩沖區。

#define ALIGN_UP(offset, alignment) \
      (offset) = ((offset) + (alignment) - 1) & ~((alignment) - 1)

char paramBuffer[1024];
size_t paramBufferSize = 0;

#define ADD_TO_PARAM_BUFFER(value, alignment)                   \
    do {                                                        \
        paramBufferSize = ALIGN_UP(paramBufferSize, alignment); \
        memcpy(paramBuffer + paramBufferSize,                   \
               &(value), sizeof(value));                        \
        paramBufferSize += sizeof(value);                       \
    } while (0)

int i;
ADD_TO_PARAM_BUFFER(i, __alignof(i));
float4 f4;
ADD_TO_PARAM_BUFFER(f4, 16); // float4's alignment is 16
char c;
ADD_TO_PARAM_BUFFER(c, __alignof(c));
float f;
ADD_TO_PARAM_BUFFER(f, __alignof(f));
CUdeviceptr devPtr;
ADD_TO_PARAM_BUFFER(devPtr, __alignof(devPtr));
float2 f2;
ADD_TO_PARAM_BUFFER(f2, 8); // float2's alignment is 8

void* extra[] = {
    CU_LAUNCH_PARAM_BUFFER_POINTER, paramBuffer,
    CU_LAUNCH_PARAM_BUFFER_SIZE,    ¶mBufferSize,
    CU_LAUNCH_PARAM_END
};
cuLaunchKernel(cuFunction,
               blockWidth, blockHeight, blockDepth,
               gridWidth, gridHeight, gridDepth,
               0, 0, 0, extra);

結構的對齊要求等于其字段的對齊要求的最大值。 因此,包含內置向量類型 CUdeviceptr 或未對齊的 double 和 long long 的結構的對齊要求可能在設備代碼和主機代碼之間有所不同。 這種結構也可以用不同的方式填充。 例如,以下結構在主機代碼中根本不填充,但在設備代碼中填充了字段 f 之后的 12 個字節,因為字段 f4 的對齊要求是 16。

typedef struct {
    float  f;
    float4 f4;
} myStruct;

L.4. Interoperability between Runtime and Driver APIs

應用程序可以將運行時 API 代碼與驅動程序 API 代碼混合。

如果通過驅動程序 API 創建上下文并使其成為當前上下文,則后續運行時調用將獲取此上下文,而不是創建新上下文。

如果運行時已初始化(如 CUDA 運行時中提到的那樣),cuCtxGetCurrent() 可用于檢索在初始化期間創建的上下文。 后續驅動程序 API 調用可以使用此上下文。

從運行時隱式創建的上下文稱為主上下文(請參閱初始化)。 它可以通過具有主要上下文管理功能的驅動程序 API 進行管理。

可以使用任一 API 分配和釋放設備內存。 CUdeviceptr 可以轉換為常規指針,反之亦然:

CUdeviceptr devPtr;
float* d_data;

// Allocation using driver API
cuMemAlloc(&devPtr, size);
d_data = (float*)devPtr;

// Allocation using runtime API
cudaMalloc(&d_data, size);
devPtr = (CUdeviceptr)d_data;

特別是,這意味著使用驅動程序 API 編寫的應用程序可以調用使用運行時 API 編寫的庫(例如 cuFFT、cuBLAS…)。

參考手冊的設備和版本管理部分的所有功能都可以互換使用。

L.5. Driver Entry Point Access

L.5.1. Introduction

驅動程序入口點訪問 API 提供了一種檢索 CUDA 驅動程序函數地址的方法。 從 CUDA 11.3 開始,用戶可以使用從這些 API 獲得的函數指針調用可用的 CUDA 驅動程序 API。

這些 API 提供的功能類似于它們的對應物,POSIX 平臺上的 dlsym 和 Windows 上的 GetProcAddress。 提供的 API 將允許用戶:

使用 CUDA 驅動程序 API 檢索驅動程序函數的地址。

使用 CUDA 運行時 API 檢索驅動程序函數的地址。

請求 CUDA 驅動程序函數的每線程默認流版本。 有關更多詳細信息,請參閱檢索每個線程的默認流版本

使用較新的驅動程序訪問舊工具包上的新 CUDA 功能。

L.5.2. Driver Function Typedefs

為了幫助檢索 CUDA 驅動程序 API 入口點,CUDA 工具包提供對包含所有 CUDA 驅動程序 API 的函數指針定義的頭文件的訪問。 這些頭文件與 CUDA Toolkit 一起安裝,并且在工具包的 include/ 目錄中可用。 下表總結了包含每個 CUDA API 頭文件的 typedef 的頭文件。Table 17. Typedefs header files for CUDA driver APIs

上面的頭文件本身并沒有定義實際的函數指針; 他們為函數指針定義了typedef。 例如,cudaTypedefs.h具有驅動 APIcuMemAlloc的以下typedef

    typedef CUresult (CUDAAPI *PFN_cuMemAlloc_v3020)(CUdeviceptr_v2 *dptr, size_t bytesize);
    typedef CUresult (CUDAAPI *PFN_cuMemAlloc_v2000)(CUdeviceptr_v1 *dptr, unsigned int bytesize);

CUDA 驅動程序符號具有基于版本的命名方案,其名稱中帶有_v*擴展名,但第一個版本除外。 當特定 CUDA 驅動程序 API 的簽名或語義發生變化時,我們會增加相應驅動程序符號的版本號。 對于cuMemAlloc驅動程序 API,第一個驅動程序符號名稱是cuMemAlloc,下一個符號名稱是cuMemAlloc_v2。 CUDA 2.0 (2000) 中引入的第一個版本的typedefPFN_cuMemAlloc_v2000。 CUDA 3.2 (3020) 中引入的下一個版本的typedefPFN_cuMemAlloc_v3020

typedef 可用于更輕松地在代碼中定義適當類型的函數指針:

    PFN_cuMemAlloc_v3020 pfn_cuMemAlloc_v2;
    PFN_cuMemAlloc_v2000 pfn_cuMemAlloc_v1;

如果用戶對 API 的特定版本感興趣,則上述方法更可取。 此外,頭文件中包含所有驅動程序符號的最新版本的預定義宏,這些驅動程序符號在安裝的 CUDA 工具包發布時可用; 這些typedef沒有_v*后綴。 對于 CUDA 11.3 工具包,cuMemAlloc_v2是最新版本,所以我們也可以定義它的函數指針如下:

  PFN_cuMemAlloc pfn_cuMemAlloc;

L.5.3. Driver Function Retrieval

使用驅動程序入口點訪問 API 和適當的 typedef,我們可以獲得指向任何 CUDA 驅動程序 API 的函數指針。

L.5.3.1. Using the driver API

驅動程序 API 需要 CUDA 版本作為參數來獲取請求的驅動程序符號的 ABI 兼容版本。 CUDA 驅動程序 API 有一個以 _v* 擴展名表示的按功能 ABI。 例如,考慮 cudaTypedefs.h 中 cuStreamBeginCapture 的版本及其對應的 typedef:

    // cuda.h
    CUresult CUDAAPI cuStreamBeginCapture(CUstream hStream);
    CUresult CUDAAPI cuStreamBeginCapture_v2(CUstream hStream, CUstreamCaptureMode mode);
            
    // cudaTypedefs.h
    typedef CUresult (CUDAAPI *PFN_cuStreamBeginCapture_v10000)(CUstream hStream);
    typedef CUresult (CUDAAPI *PFN_cuStreamBeginCapture_v10010)(CUstream hStream, CUstreamCaptureMode mode);

從上述代碼片段中的typedefs,版本后綴_v10000_v10010表示上述API分別在CUDA 10.0CUDA 10.1中引入。

    #include 
    
    // Declare the entry points for cuStreamBeginCapture
    PFN_cuStreamBeginCapture_v10000 pfn_cuStreamBeginCapture_v1;
    PFN_cuStreamBeginCapture_v10010 pfn_cuStreamBeginCapture_v2;
    
    // Get the function pointer to the cuStreamBeginCapture driver symbol
    cuGetProcAddress("cuStreamBeginCapture", &pfn_cuStreamBeginCapture_v1, 10000, CU_GET_PROC_ADDRESS_DEFAULT);
    // Get the function pointer to the cuStreamBeginCapture_v2 driver symbol
    cuGetProcAddress("cuStreamBeginCapture", &pfn_cuStreamBeginCapture_v2, 10010, CU_GET_PROC_ADDRESS_DEFAULT);

參考上面的代碼片段,要檢索到驅動程序 API cuStreamBeginCapture 的 _v1 版本的地址,CUDA 版本參數應該正好是 10.0 (10000)。同樣,用于檢索 _v2 版本 API 的地址的 CUDA 版本應該是 10.1 (10010)。為檢索特定版本的驅動程序 API 指定更高的 CUDA 版本可能并不總是可移植的。例如,在此處使用 11030 仍會返回 _v2 符號,但如果在 CUDA 11.3 中發布假設的 _v3 版本,則當與 CUDA 11.3 驅動程序配對時,cuGetProcAddress API 將開始返回較新的 _v3 符號。由于 _v2 和 _v3 符號的 ABI 和函數簽名可能不同,使用用于 _v2 符號的 _v10010 typedef 調用 _v3 函數將表現出未定義的行為。

要檢索給定 CUDA 工具包的驅動程序 API 的最新版本,我們還可以指定 CUDA_VERSION 作為版本參數,并使用未版本化的 typedef 來定義函數指針。由于 _v2 是 CUDA 11.3 中驅動程序 API cuStreamBeginCapture 的最新版本,因此下面的代碼片段顯示了檢索它的不同方法。

    // Assuming we are using CUDA 11.3 Toolkit

    #include 
    
    // Declare the entry point
    PFN_cuStreamBeginCapture pfn_cuStreamBeginCapture_latest;
    
    // Intialize the entry point. Specifying CUDA_VERSION will give the function pointer to the
    // cuStreamBeginCapture_v2 symbol since it is latest version on CUDA 11.3.
    cuGetProcAddress("cuStreamBeginCapture", &pfn_cuStreamBeginCapture_latest, CUDA_VERSION, CU_GET_PROC_ADDRESS_DEFAULT);
  

請注意,請求具有無效 CUDA 版本的驅動程序 API 將返回錯誤 CUDA_ERROR_NOT_FOUND。 在上面的代碼示例中,傳入小于 10000 (CUDA 10.0) 的版本將是無效的。

L.5.3.2. Using the runtime API

運行時 API 使用 CUDA 運行時版本來獲取請求的驅動程序符號的 ABI 兼容版本。 在下面的代碼片段中,所需的最低 CUDA 運行時版本將是 CUDA 11.2,因為當時引入了 cuMemAllocAsync。

    #include 
    
    // Declare the entry point
    PFN_cuMemAllocAsync pfn_cuMemAllocAsync;
    
    // Intialize the entry point. Assuming CUDA runtime version >= 11.2
    cudaGetDriverEntryPoint("cuMemAllocAsync", &pfn_cuMemAllocAsync, cudaEnableDefault);
    
    // Call the entry point
    pfn_cuMemAllocAsync(...);

L.5.3.3. Retrieve per-thread default stream versions

一些 CUDA 驅動程序 API 可以配置為具有默認流或每線程默認流語義。具有每個線程默認流語義的驅動程序 API 在其名稱中以 _ptsz 或 _ptds 為后綴。例如,cuLaunchKernel 有一個名為 cuLaunchKernel_ptsz 的每線程默認流變體。使用驅動程序入口點訪問 API,用戶可以請求驅動程序 API cuLaunchKernel 的每線程默認流版本,而不是默認流版本。為默認流或每線程默認流語義配置 CUDA 驅動程序 API 會影響同步行為。更多詳細信息可以在這里找到。

驅動API的默認流或每線程默認流版本可以通過以下方式之一獲得:

使用編譯標志 --default-stream per-thread 或定義宏 CUDA_API_PER_THREAD_DEFAULT_STREAM 以獲取每個線程的默認流行為。

分別使用標志 CU_GET_PROC_ADDRESS_LEGACY_STREAM/cudaEnableLegacyStream 或 CU_GET_PROC_ADDRESS_PER_THREAD_DEFAULT_STREAM/cudaEnablePerThreadDefaultStream 強制默認流或每個線程的默認流行為。

L.5.3.4. Access new CUDA features

始終建議安裝最新的 CUDA 工具包以訪問新的 CUDA 驅動程序功能,但如果出于某種原因,用戶不想更新或無法訪問最新的工具包,則可以使用 API 來訪問新的 CUDA 功能 只有更新的 CUDA 驅動程序。 為了討論,讓我們假設用戶使用 CUDA 11.3,并希望使用 CUDA 12.0 驅動程序中提供的新驅動程序 API cuFoo。 下面的代碼片段說明了這個用例:

    int main()
    {
        // Assuming we have CUDA 12.0 driver installed.

        // Manually define the prototype as cudaTypedefs.h in CUDA 11.3 does not have the cuFoo typedef
        typedef CUresult (CUDAAPI *PFN_cuFoo)(...);
        PFN_cuFoo pfn_cuFoo = NULL;
        
        // Get the address for cuFoo API using cuGetProcAddress. Specify CUDA version as
        // 12000 since cuFoo was introduced then or get the driver version dynamically
        // using cuDriverGetVersion 
        int driverVersion;
        cuDriverGetVersion(&driverVersion);
        cuGetProcAddress("cuFoo", &pfn_cuFoo, driverVersion, CU_GET_PROC_ADDRESS_DEFAULT);
        
        if (pfn_cuFoo) {
            pfn_cuFoo(...);
        }
        else {
            printf("Cannot retrieve the address to cuFoo. Check if the latest driver for CUDA 12.0 is installed.\n");
            assert(0);
        }
        
        // rest of code here
        
    

關于作者

Ken He 是 NVIDIA 企業級開發者社區經理 & 高級講師,擁有多年的 GPU人工智能開發經驗。自 2017 年加入 NVIDIA 開發者社區以來,完成過上百場培訓,幫助上萬個開發者了解人工智能和 GPU 編程開發。在計算機視覺,高性能計算領域完成過多個獨立項目。并且,在機器人無人機領域,有過豐富的研發經驗。對于圖像識別,目標的檢測與跟蹤完成過多種解決方案。曾經參與 GPU 版氣象模式GRAPES,是其主要研發者。

審核編輯:郭婷

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • API
    API
    +關注

    關注

    2

    文章

    2375

    瀏覽量

    66805
  • 應用程序
    +關注

    關注

    38

    文章

    3344

    瀏覽量

    60272
  • CUDA
    +關注

    關注

    0

    文章

    127

    瀏覽量

    14482
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    JH7110 什么時候支持 Vulkan API?

    驅動器還不完美,但我認為 vulkan 更重要,我希望盡快開始與 IMG 合作支持 vulkan 驅動程序
    發表于 01-26 06:11

    拼多多API應用:社交分享驅動銷量飆升!

    ? 在當今社交電商時代,拼多多憑借其獨特的社交分享機制,成為電商領域的佼佼者。其開放平臺提供的API(應用程序接口)允許開發者輕松集成社交分享功能,從而通過好友互動、病毒式傳播顯著提升商品銷量。本文
    的頭像 發表于 12-24 15:43 ?297次閱讀
    拼多多<b class='flag-5'>API</b>應用:社交分享<b class='flag-5'>驅動</b>銷量飆升!

    為FreeRTOS增加新的設備驅動程序

    如果你正在使用FreeRTOS構建嵌入式系統,并且考慮添加新的設備驅動程序,那么這篇文章很適合你。高效的設備集成不僅僅是讓設備功能正常運行——更關乎模塊化、可靠性和安全性。
    的頭像 發表于 08-06 15:44 ?1002次閱讀
    為FreeRTOS增加新的設備<b class='flag-5'>驅動程序</b>

    zephyr設備驅動程序模型

    系統中的所有驅動程序。 每種類型的驅動程序(例如 UART、SPI、I2C)都由通用類型 API 支持。 在此模型中,驅動程序驅動程序初始
    的頭像 發表于 07-29 10:34 ?705次閱讀
    zephyr設備<b class='flag-5'>驅動程序</b>模型

    請問如何創建在 RAM 區域完全獨立運行的閃存驅動程序代碼?

    獨立,我已經盡可能的避免調用位于FLASH上的API,但似乎還是不行。我想問一下我應該如何制作flash驅動程序?有沒有任何可用的演示參考?下面是我的閃存驅動程序代碼的一部分。 “ uint16 結束
    發表于 07-25 07:33

    如何安裝 CY7C65213 的驅動程序?

    無法連接 teraterm。 我嘗試安裝 CypressDriverInstaller_1,但是驅動程序沒有更新。 你能指導如何安裝 CY7C65213 的驅動程序嗎?
    發表于 05-27 07:58

    如何處理FX3 USB驅動程序與MFI相關接口的安裝?

    USB 電纜將設備(沒有 PMODE 的 SPI 引腳)連接到 PC(USB 2.0)并為 WestBridge 設備安裝驅動程序時,在斷開設備與 PC 的連接并重新連接后,驅動程序會在幾秒鐘后從
    發表于 05-23 07:54

    CY4500 EZ-PD協議分析儀缺少驅動程序怎么解決?

    Win10 CY4500 Analyzer 4.0.0 安裝程序似乎不包含硬件驅動程序。固件更新實用程序或 CY4500 產品頁面上的支持部分也是如此。顯然沒有驅動程序
    發表于 05-23 06:43

    是否提供適用于CY7C65213 的 Windows 11驅動程序API 庫 (dll)?

    您好,支持, 我對 Infineon(原 Cypress)生產的 USB 串行 IC 有疑問。 是否提供適用于 CY7C65213 的 Windows 11 驅動程序API 庫 (dll
    發表于 05-15 07:26

    何在Android設備上安裝Cyusb3014芯片驅動

    1.如何在Android設備上安裝Cyusb3014芯片驅動? 我們在 Windows 上有 FX3 驅動程序 SDK。 2.如何在Android系統上下載固件到芯片中?
    發表于 05-15 07:23

    3014 USB驅動程序無法檢測到USB設備是怎么回事?

    我已將我的 USB 設備連接到運行 Windows 10 X64 的計算機,我已嘗試使用 1.2.3 和 1.3.0 版本的 cyapi 和 USB 驅動程序。 有時CYPRESS? API 的設備
    發表于 05-09 06:11

    是否有辦法用標準Windows驅動程序控制GPIO嗎?

    關于 CY7C65213-28PVXI 的控制, 我正在考慮更改 VenderID 并使用標準 Windows 驅動程序對其進行控制。 但是,使用標準 Windows 驅動程序存在一個
    發表于 05-08 07:05

    Linux環境再升級:PLIN驅動程序正式發布

    PLIN驅動程序現已正式發布,本文將展示如何安裝PLIN驅動程序,以及如何在Linux環境下進行基本的PLIN通信操作,確保您能夠快速掌握并應用這一新工具。
    的頭像 發表于 04-21 15:29 ?1065次閱讀
    Linux環境再升級:PLIN<b class='flag-5'>驅動程序</b>正式發布

    如何使用MCAL的TJA1145實現驅動程序?

    你好: 我希望使用 MCAL 的 TJA1145 實現驅動程序,您能幫我嗎
    發表于 04-03 06:50

    RTC芯片有Linux PCA2131驅動程序嗎?

    RTC 芯片有 Linux PCA2131驅動程序嗎? 1) 如果沒有,我可以使用任何兼容的驅動程序驅動這個 RTC 芯片嗎? 2) 如果是,我在哪里可以找到它?
    發表于 03-31 06:22