色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

分配器支持在進(jìn)程間輕松安全地共享分配

星星科技指導(dǎo)員 ? 來源:NVIDIA ? 作者:Ken He ? 2022-04-28 09:42 ? 次閱讀

F.1. Introduction

使用 cudaMalloc 和 cudaFree 管理內(nèi)存分配會導(dǎo)致 GPU 在所有正在執(zhí)行的 CUDA 流之間進(jìn)行同步。 Stream Order Memory Allocator 使應(yīng)用程序能夠通過啟動到 CUDA 流中的其他工作(例如內(nèi)核啟動和異步拷貝)來對內(nèi)存分配和釋放進(jìn)行排序。這通過利用流排序語義來重用內(nèi)存分配來改進(jìn)應(yīng)用程序內(nèi)存使用。分配器還允許應(yīng)用程序控制分配器的內(nèi)存緩存行為。當(dāng)設(shè)置了適當(dāng)?shù)尼尫砰撝禃r,緩存行為允許分配器在應(yīng)用程序表明它愿意接受更大的內(nèi)存占用時避免對操作系統(tǒng)進(jìn)行昂貴的調(diào)用。分配器還支持在進(jìn)程之間輕松安全地共享分配。

對于許多應(yīng)用程序,Stream Ordered Memory Allocator 減少了對自定義內(nèi)存管理抽象的需求,并使為需要它的應(yīng)用程序創(chuàng)建高性能自定義內(nèi)存管理變得更加容易。對于已經(jīng)具有自定義內(nèi)存分配器的應(yīng)用程序和庫,采用 Stream Ordered Memory Allocator 可以使多個庫共享由驅(qū)動程序管理的公共內(nèi)存池,從而減少過多的內(nèi)存消耗。此外,驅(qū)動程序可以根據(jù)其對分配器和其他流管理 API 的感知執(zhí)行優(yōu)化。最后,Nsight Compute 和 Next-Gen CUDA 調(diào)試器知道分配器是其 CUDA 11.3 工具包支持的一部分。

F.2. Query for Support

用戶可以通過使用設(shè)備屬性 cudaDevAttrMemoryPoolsSupported 調(diào)用 cudaDeviceGetAttribute() 來確定設(shè)備是否支持流序內(nèi)存分配器。

從 CUDA 11.3 開始,可以使用 cudaDevAttrMemoryPoolSupportedHandleTypes 設(shè)備屬性查詢 IPC 內(nèi)存池支持。 以前的驅(qū)動程序?qū)⒎祷?cudaErrorInvalidValue,因為這些驅(qū)動程序不知道屬性枚舉。

int driverVersion = 0;
int deviceSupportsMemoryPools = 0;
int poolSupportedHandleTypes = 0;
cudaDriverGetVersion(&driverVersion);
if (driverVersion >= 11020) {
    cudaDeviceGetAttribute(&deviceSupportsMemoryPools,
                           cudaDevAttrMemoryPoolsSupported, device);
}
if (deviceSupportsMemoryPools != 0) {
    // `device` supports the Stream Ordered Memory Allocator
}

if (driverVersion >= 11030) {
    cudaDeviceGetAttribute(&poolSupportedHandleTypes,
              cudaDevAttrMemoryPoolSupportedHandleTypes, device);
}
if (poolSupportedHandleTypes & cudaMemHandleTypePosixFileDescriptor) {
   // Pools on the specified device can be created with posix file descriptor-based IPC
}

在查詢之前執(zhí)行驅(qū)動程序版本檢查可避免在尚未定義屬性的驅(qū)動程序上遇到 cudaErrorInvalidValue 錯誤。 可以使用 cudaGetLastError 來清除錯誤而不是避免它。

F.3. API Fundamentals (cudaMallocAsync and cudaFreeAsync)

API cudaMallocAsync 和 cudaFreeAsync 構(gòu)成了分配器的核心。 cudaMallocAsync 返回分配,cudaFreeAsync 釋放分配。 兩個 API 都接受流參數(shù)來定義分配何時變?yōu)榭捎煤屯V箍捎谩?cudaMallocAsync 返回的指針值是同步確定的,可用于構(gòu)建未來的工作。 重要的是要注意 cudaMallocAsync 在確定分配的位置時會忽略當(dāng)前設(shè)備/上下文。 相反,cudaMallocAsync 根據(jù)指定的內(nèi)存池或提供的流來確定常駐設(shè)備。 最簡單的使用模式是分配、使用和釋放內(nèi)存到同一個流中。

void *ptr;
size_t size = 512;
cudaMallocAsync(&ptr, size, cudaStreamPerThread);
// do work using the allocation
kernel<<<..., cudaStreamPerThread>>>(ptr, ...);
// An asynchronous free can be specified without synchronizing the CPU and GPU
cudaFreeAsync(ptr, cudaStreamPerThread);

用戶可以使用cudaFreeAsync()釋放使用cudaMalloc()分配的內(nèi)存。 在自由操作開始之前,用戶必須對訪問完成做出同樣的保證。

cudaMalloc(&ptr, size);
kernel<<<..., stream>>>(ptr, ...);
cudaFreeAsync(ptr, stream);

用戶可以使用cudaFree()釋放使用cudaMallocAsync分配的內(nèi)存。 通過cudaFree()API 釋放此類分配時,驅(qū)動程序假定對分配的所有訪問都已完成,并且不執(zhí)行進(jìn)一步的同步。 用戶可以使用cudaStreamQuery / cudaStreamSynchronize / cudaEventQuery / cudaEventSynchronize / cudaDeviceSynchronize來保證適當(dāng)?shù)漠惒焦ぷ魍瓿刹⑶褿PU不會嘗試訪問分配。

cudaMallocAsync(&ptr, size,stream);
kernel<<<..., stream>>>(ptr, ...);
// synchronize is needed to avoid prematurely freeing the memory
cudaStreamSynchronize(stream);
cudaFree(ptr);

F.4. Memory Pools and the cudaMemPool_t

內(nèi)存池封裝了虛擬地址和物理內(nèi)存資源,根據(jù)內(nèi)存池的屬性和屬性進(jìn)行分配和管理。內(nèi)存池的主要方面是它所管理的內(nèi)存的種類和位置。

所有對 cudaMallocAsync 的調(diào)用都使用內(nèi)存池的資源。在沒有指定內(nèi)存池的情況下,cudaMallocAsync API 使用提供的流設(shè)備的當(dāng)前內(nèi)存池。設(shè)備的當(dāng)前內(nèi)存池可以使用 cudaDeviceSetMempool 設(shè)置并使用 cudaDeviceGetMempool 查詢。默認(rèn)情況下(在沒有 cudaDeviceSetMempool 調(diào)用的情況下),當(dāng)前內(nèi)存池是設(shè)備的默認(rèn)內(nèi)存池。 cudaMallocFromPoolAsync 的 API cudaMallocFromPoolAsync 和 c++ 重載允許用戶指定要用于分配的池,而無需將其設(shè)置為當(dāng)前池。 API cudaDeviceGetDefaultMempool 和 cudaMemPoolCreate 為用戶提供內(nèi)存池的句柄。

注意:設(shè)備的內(nèi)存池當(dāng)前將是該設(shè)備的本地。因此,在不指定內(nèi)存池的情況下進(jìn)行分配將始終產(chǎn)生流設(shè)備本地的分配。

注意:cudaMemPoolSetAttribute 和 cudaMemPoolGetAttribute 控制內(nèi)存池的屬性。

F.5. Default/Impicit Pools

可以使用 cudaDeviceGetDefaultMempool API 檢索設(shè)備的默認(rèn)內(nèi)存池。 來自設(shè)備默認(rèn)內(nèi)存池的分配是位于該設(shè)備上的不可遷移設(shè)備分配。 這些分配將始終可以從該設(shè)備訪問。 默認(rèn)內(nèi)存池的可訪問性可以通過 cudaMemPoolSetAccess 進(jìn)行修改,并通過 cudaMemPoolGetAccess 進(jìn)行查詢。 由于不需要顯式創(chuàng)建默認(rèn)池,因此有時將它們稱為隱式池。 設(shè)備默認(rèn)內(nèi)存池不支持IPC。

F.6. Explicit Pools

API cudaMemPoolCreate 創(chuàng)建一個顯式池。 目前內(nèi)存池只能分配設(shè)備分配。 分配將駐留的設(shè)備必須在屬性結(jié)構(gòu)中指定。 顯式池的主要用例是 IPC 功能。

// create a pool similar to the implicit pool on device 0
int device = 0;
cudaMemPoolProps poolProps = { };
poolProps.allocType = cudaMemAllocationTypePinned;
poolProps.location.id = device;
poolProps.location.type = cudaMemLocationTypeDevice;

cudaMemPoolCreate(&memPool, &poolProps));

F.7. Physical Page Caching Behavior

默認(rèn)情況下,分配器嘗試最小化池?fù)碛械奈锢韮?nèi)存。 為了盡量減少分配和釋放物理內(nèi)存的操作系統(tǒng)調(diào)用,應(yīng)用程序必須為每個池配置內(nèi)存占用。 應(yīng)用程序可以使用釋放閾值屬性 (cudaMemPoolAttrReleaseThreshold) 執(zhí)行此操作。

釋放閾值是池在嘗試將內(nèi)存釋放回操作系統(tǒng)之前應(yīng)保留的內(nèi)存量(以字節(jié)為單位)。 當(dāng)內(nèi)存池持有超過釋放閾值字節(jié)的內(nèi)存時,分配器將嘗試在下一次調(diào)用流、事件或設(shè)備同步時將內(nèi)存釋放回操作系統(tǒng)。 將釋放閾值設(shè)置為 UINT64_MAX 將防止驅(qū)動程序在每次同步后嘗試收縮池。

Cuuint64_t setVal = UINT64_MAX;
cudaMemPoolSetAttribute(memPool, cudaMemPoolAttrReleaseThreshold, &setVal);

cudaMemPoolAttrReleaseThreshold設(shè)置得足夠高以有效禁用內(nèi)存池收縮的應(yīng)用程序可能希望顯式收縮內(nèi)存池的內(nèi)存占用。cudaMemPoolTrimTo允許此類應(yīng)用程序這樣做。 在修剪內(nèi)存池的占用空間時,minBytesToKeep參數(shù)允許應(yīng)用程序保留它預(yù)期在后續(xù)執(zhí)行階段需要的內(nèi)存量。

Cuuint64_t setVal = UINT64_MAX;
cudaMemPoolSetAttribute(memPool, cudaMemPoolAttrReleaseThreshold, &setVal);

// application phase needing a lot of memory from the stream ordered allocator
for (i=0; i<10; i++) {
    for (j=0; j<10; j++) {
        cudaMallocAsync(&ptrs[j],size[j], stream);
    }
    kernel<<<...,stream>>>(ptrs,...);
    for (j=0; j<10; j++) {
        cudaFreeAsync(ptrs[j], stream);
    }
}

// Process does not need as much memory for the next phase.
// Synchronize so that the trim operation will know that the allocations are no 
// longer in use.
cudaStreamSynchronize(stream);
cudaMemPoolTrimTo(mempool, 0);

// Some other process/allocation mechanism can now use the physical memory 
// released by the trimming operation.

F.8. Resource Usage Statistics

在 CUDA 11.3 中,添加了池屬性 cudaMemPoolAttrReservedMemCurrent、cudaMemPoolAttrReservedMemHigh、cudaMemPoolAttrUsedMemCurrent 和 cudaMemPoolAttrUsedMemHigh 來查詢池的內(nèi)存使用情況。

查詢池的 cudaMemPoolAttrReservedMemCurrent 屬性會報告該池當(dāng)前消耗的總物理 GPU 內(nèi)存。 查詢池的 cudaMemPoolAttrUsedMemCurrent 會返回從池中分配且不可重用的所有內(nèi)存的總大小。

cudaMemPoolAttr*MemHigh 屬性是記錄自上次重置以來各個 cudaMemPoolAttr*MemCurrent 屬性達(dá)到的最大值的水印。 可以使用 cudaMemPoolSetAttribute API 將它們重置為當(dāng)前值。

// sample helper functions for getting the usage statistics in bulk
struct usageStatistics {
    cuuint64_t reserved;
    cuuint64_t reservedHigh;
    cuuint64_t used;
    cuuint64_t usedHigh;
};

void getUsageStatistics(cudaMemoryPool_t memPool, struct usageStatistics *statistics)
{
    cudaMemPoolGetAttribute(memPool, cudaMemPoolAttrReservedMemCurrent, statistics->reserved);
    cudaMemPoolGetAttribute(memPool, cudaMemPoolAttrReservedMemHigh, statistics->reservedHigh);
    cudaMemPoolGetAttribute(memPool, cudaMemPoolAttrUsedMemCurrent, statistics->used);
    cudaMemPoolGetAttribute(memPool, cudaMemPoolAttrUsedMemHigh, statistics->usedHigh);
}


// resetting the watermarks will make them take on the current value.
void resetStatistics(cudaMemoryPool_t memPool)
{
    cuuint64_t value = 0;
    cudaMemPoolSetAttribute(memPool, cudaMemPoolAttrReservedMemHigh, &value);
    cudaMemPoolSetAttribute(memPool, cudaMemPoolAttrUsedMemHigh, &value);
}

F.9. Memory Reuse Policies

為了服務(wù)分配請求,驅(qū)動程序在嘗試從操作系統(tǒng)分配更多內(nèi)存之前嘗試重用之前通過 cudaFreeAsync() 釋放的內(nèi)存。 例如,流中釋放的內(nèi)存可以立即重新用于同一流中的后續(xù)分配請求。 類似地,當(dāng)一個流與 CPU 同步時,之前在該流中釋放的內(nèi)存可以重新用于任何流中的分配。

流序分配器有一些可控的分配策略。 池屬性 cudaMemPoolReuseFollowEventDependencies、cudaMemPoolReuseAllowOpportunistic 和 cudaMemPoolReuseAllowInternalDependencies 控制這些策略。 升級到更新的 CUDA 驅(qū)動程序可能會更改、增強(qiáng)、增加或重新排序重用策略。

F.9.1. cudaMemPoolReuseFollowEventDependencies

在分配更多物理 GPU 內(nèi)存之前,分配器會檢查由 CUDA 事件建立的依賴信息,并嘗試從另一個流中釋放的內(nèi)存中進(jìn)行分配。

cudaMallocAsync(&ptr, size, originalStream);
kernel<<<..., originalStream>>>(ptr, ...);
cudaFreeAsync(ptr, originalStream);
cudaEventRecord(event,originalStream);

// waiting on the event that captures the free in another stream 
// allows the allocator to reuse the memory to satisfy 
// a new allocation request in the other stream when
// cudaMemPoolReuseFollowEventDependencies is enabled.
cudaStreamWaitEvent(otherStream, event);
cudaMallocAsync(&ptr2, size, otherStream);

F.9.2. cudaMemPoolReuseAllowOpportunistic

根據(jù) cudaMemPoolReuseAllowOpportunistic 策略,分配器檢查釋放的分配以查看是否滿足釋放的流序語義(即流已通過釋放指示的執(zhí)行點)。 禁用此功能后,分配器仍將重用在流與 cpu 同步時可用的內(nèi)存。 禁用此策略不會阻止 cudaMemPoolReuseFollowEventDependencies 應(yīng)用。

cudaMallocAsync(&ptr, size, originalStream);
kernel<<<..., originalStream>>>(ptr, ...);
cudaFreeAsync(ptr, originalStream);


// after some time, the kernel finishes running
wait(10);

// When cudaMemPoolReuseAllowOpportunistic is enabled this allocation request
// can be fulfilled with the prior allocation based on the progress of originalStream.
cudaMallocAsync(&ptr2, size, otherStream);

F.9.3. cudaMemPoolReuseAllowInternalDependencies

如果無法從操作系統(tǒng)分配和映射更多物理內(nèi)存,驅(qū)動程序?qū)ふ移淇捎眯匀Q于另一個流的待處理進(jìn)度的內(nèi)存。 如果找到這樣的內(nèi)存,驅(qū)動程序會將所需的依賴項插入分配流并重用內(nèi)存。

cudaMallocAsync(&ptr, size, originalStream);
kernel<<<..., originalStream>>>(ptr, ...);
cudaFreeAsync(ptr, originalStream);

// When cudaMemPoolReuseAllowInternalDependencies is enabled
// and the driver fails to allocate more physical memory, the driver may
// effectively perform a cudaStreamWaitEvent in the allocating stream
// to make sure that future work in ‘otherStream’ happens after the work
// in the original stream that would be allowed to access the original allocation. 
cudaMallocAsync(&ptr2, size, otherStream);

F.9.4. Disabling Reuse Policies

雖然可控重用策略提高了內(nèi)存重用,但用戶可能希望禁用它們。 允許機(jī)會重用(即 cudaMemPoolReuseAllowOpportunistic)基于 CPU 和 GPU 執(zhí)行的交錯引入了運行到運行分配模式的差異。 當(dāng)用戶寧愿在分配失敗時顯式同步事件或流時,內(nèi)部依賴插入(即 cudaMemPoolReuseAllowInternalDependencies)可以以意想不到的和潛在的非確定性方式序列化工作。

F.10. Device Accessibility for Multi-GPU Support

就像通過虛擬內(nèi)存管理 API 控制的分配可訪問性一樣,內(nèi)存池分配可訪問性不遵循 cudaDeviceEnablePeerAccess 或 cuCtxEnablePeerAccess。相反,API cudaMemPoolSetAccess 修改了哪些設(shè)備可以訪問池中的分配。默認(rèn)情況下,可以從分配所在的設(shè)備訪問分配。無法撤銷此訪問權(quán)限。要啟用其他設(shè)備的訪問,訪問設(shè)備必須與內(nèi)存池的設(shè)備對等;檢查 cudaDeviceCanAccessPeer。如果未檢查對等功能,則設(shè)置訪問可能會失敗并顯示 cudaErrorInvalidDevice。如果沒有從池中進(jìn)行分配,即使設(shè)備不具備對等能力,cudaMemPoolSetAccess 調(diào)用也可能成功;在這種情況下,池中的下一次分配將失敗。

值得注意的是,cudaMemPoolSetAccess 會影響內(nèi)存池中的所有分配,而不僅僅是未來的分配。此外,cudaMemPoolGetAccess 報告的可訪問性適用于池中的所有分配,而不僅僅是未來的分配。建議不要頻繁更改給定 GPU 的池的可訪問性設(shè)置;一旦池可以從給定的 GPU 訪問,它應(yīng)該在池的整個生命周期內(nèi)都可以從該 GPU 訪問。

// snippet showing usage of cudaMemPoolSetAccess:
cudaError_t setAccessOnDevice(cudaMemPool_t memPool, int residentDevice,
              int accessingDevice) {
    cudaMemAccessDesc accessDesc = {};
    accessDesc.location.type = cudaMemLocationTypeDevice;
    accessDesc.location.id = accessingDevice;
    accessDesc.flags = cudaMemAccessFlagsProtReadWrite;

    int canAccess = 0;
    cudaError_t error = cudaDeviceCanAccessPeer(&canAccess, accessingDevice,
              residentDevice);
    if (error != cudaSuccess) {
        return error;
    } else if (canAccess == 0) {
        return cudaErrorPeerAccessUnsupported;
    }

    // Make the address accessible
    return cudaMemPoolSetAccess(memPool, &accessDesc, 1);
}

F.11. IPC Memory Pools

支持 IPC 的內(nèi)存池允許在進(jìn)程之間輕松、高效和安全地共享 GPU 內(nèi)存。 CUDA 的 IPC 內(nèi)存池提供與 CUDA 的虛擬內(nèi)存管理 API 相同的安全優(yōu)勢。

在具有內(nèi)存池的進(jìn)程之間共享內(nèi)存有兩個階段。 進(jìn)程首先需要共享對池的訪問權(quán)限,然后共享來自該池的特定分配。 第一階段建立并實施安全性。 第二階段協(xié)調(diào)每個進(jìn)程中使用的虛擬地址以及映射何時需要在導(dǎo)入過程中有效。

F.11.1. Creating and Sharing IPC Memory Pools

共享對池的訪問涉及檢索池的 OS 本機(jī)句柄(使用 cudaMemPoolExportToShareableHandle() API),使用通常的 OS 本機(jī) IPC 機(jī)制將句柄轉(zhuǎn)移到導(dǎo)入進(jìn)程,并創(chuàng)建導(dǎo)入的內(nèi)存池(使用 cudaMemPoolImportFromShareableHandle() API)。 要使 cudaMemPoolExportToShareableHandle 成功,必須使用池屬性結(jié)構(gòu)中指定的請求句柄類型創(chuàng)建內(nèi)存池。 請參考示例以了解在進(jìn)程之間傳輸操作系統(tǒng)本機(jī)句柄的適當(dāng) IPC 機(jī)制。 該過程的其余部分可以在以下代碼片段中找到。

// in exporting process
// create an exportable IPC capable pool on device 0
cudaMemPoolProps poolProps = { };
poolProps.allocType = cudaMemAllocationTypePinned;
poolProps.location.id = 0;
poolProps.location.type = cudaMemLocationTypeDevice;

// Setting handleTypes to a non zero value will make the pool exportable (IPC capable)
poolProps.handleTypes = CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR;

cudaMemPoolCreate(&memPool, &poolProps));

// FD based handles are integer types
int fdHandle = 0;


// Retrieve an OS native handle to the pool.
// Note that a pointer to the handle memory is passed in here.
cudaMemPoolExportToShareableHandle(&fdHandle,
             memPool,
             CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR,
             0);

// The handle must be sent to the importing process with the appropriate
// OS specific APIs.
// in importing process
 int fdHandle;
// The handle needs to be retrieved from the exporting process with the
// appropriate OS specific APIs.
// Create an imported pool from the shareable handle.
// Note that the handle is passed by value here. 
cudaMemPoolImportFromShareableHandle(&importedMemPool,
          (void*)fdHandle,
          CU_MEM_HANDLE_TYPE_POSIX_FILE_DESCRIPTOR,
          0);

F.11.2. Set Access in the Importing Process

導(dǎo)入的內(nèi)存池最初只能從其常駐設(shè)備訪問。 導(dǎo)入的內(nèi)存池不繼承導(dǎo)出進(jìn)程設(shè)置的任何可訪問性。 導(dǎo)入過程需要啟用從它計劃訪問內(nèi)存的任何 GPU 的訪問(使用 cudaMemPoolSetAccess)。

如果導(dǎo)入的內(nèi)存池在導(dǎo)入過程中屬于不可見的設(shè)備,則用戶必須使用 cudaMemPoolSetAccess API 來啟用從將使用分配的 GPU 的訪問。

F.11.3. Creating and Sharing Allocations from an Exported Pool

共享池后,在導(dǎo)出進(jìn)程中使用 cudaMallocAsync() 從池中進(jìn)行的分配可以與已導(dǎo)入池的其他進(jìn)程共享。由于池的安全策略是在池級別建立和驗證的,操作系統(tǒng)不需要額外的簿記來為特定的池分配提供安全性;換句話說,導(dǎo)入池分配所需的不透明 cudaMemPoolPtrExportData 可以使用任何機(jī)制發(fā)送到導(dǎo)入進(jìn)程。

雖然分配可以在不以任何方式與分配流同步的情況下導(dǎo)出甚至導(dǎo)入,但在訪問分配時,導(dǎo)入過程必須遵循與導(dǎo)出過程相同的規(guī)則。即,對分配的訪問必須發(fā)生在分配流中分配操作的流排序之后。以下兩個代碼片段顯示 cudaMemPoolExportPointer() 和 cudaMemPoolImportPointer() 與 IPC 事件共享分配,用于保證在分配準(zhǔn)備好之前在導(dǎo)入過程中不會訪問分配。

// preparing an allocation in the exporting process
cudaMemPoolPtrExportData exportData;
cudaEvent_t readyIpcEvent;
cudaIpcEventHandle_t readyIpcEventHandle;

// IPC event for coordinating between processes
// cudaEventInterprocess flag makes the event an IPC event
// cudaEventDisableTiming  is set for performance reasons

cudaEventCreate(
        &readyIpcEvent, cudaEventDisableTiming | cudaEventInterprocess)

// allocate from the exporting mem pool
cudaMallocAsync(&ptr, size,exportMemPool, stream);

// event for sharing when the allocation is ready.
cudaEventRecord(readyIpcEvent, stream);
cudaMemPoolExportPointer(&exportData, ptr);
cudaIpcGetEventHandle(&readyIpcEventHandle, readyIpcEvent);

// Share IPC event and pointer export data with the importing process using
//  any mechanism. Here we copy the data into shared memory
shmem->ptrData = exportData;
shmem->readyIpcEventHandle = readyIpcEventHandle;
// signal consumers data is ready
// Importing an allocation
cudaMemPoolPtrExportData *importData = &shmem->prtData;
cudaEvent_t readyIpcEvent;
cudaIpcEventHandle_t *readyIpcEventHandle = &shmem->readyIpcEventHandle;

// Need to retrieve the IPC event handle and the export data from the
// exporting process using any mechanism.  Here we are using shmem and just
// need synchronization to make sure the shared memory is filled in.

cudaIpcOpenEventHandle(&readyIpcEvent, readyIpcEventHandle);

// import the allocation. The operation does not block on the allocation being ready.
cudaMemPoolImportPointer(&ptr, importedMemPool, importData);

// Wait for the prior stream operations in the allocating stream to complete before
// using the allocation in the importing process.
cudaStreamWaitEvent(stream, readyIpcEvent);
kernel<<<..., stream>>>(ptr, ...);

釋放分配時,需要先在導(dǎo)入過程中釋放分配,然后在導(dǎo)出過程中釋放分配。 以下代碼片段演示了使用 CUDA IPC 事件在兩個進(jìn)程中的cudaFreeAsync操作之間提供所需的同步。 導(dǎo)入過程中對分配的訪問顯然受到導(dǎo)入過程側(cè)的自由操作的限制。 值得注意的是,cudaFree可用于釋放兩個進(jìn)程中的分配,并且可以使用其他流同步 API 代替 CUDA IPC 事件。

// The free must happen in importing process before the exporting process
kernel<<<..., stream>>>(ptr, ...); 

// Last access in importing process
cudaFreeAsync(ptr, stream); 

// Access not allowed in the importing process after the free
cudaIpcEventRecord(finishedIpcEvent, stream);
// Exporting process
// The exporting process needs to coordinate its free with the stream order 
// of the importing process’s free.
cudaStreamWaitEvent(stream, finishedIpcEvent);
kernel<<<..., stream>>>(ptrInExportingProcess, ...); 

// The free in the importing process doesn’t stop the exporting process 
// from using the allocation.
cudFreeAsync(ptrInExportingProcess,stream);

F.11.4. IPC Export Pool Limitations

IPC 池目前不支持將物理塊釋放回操作系統(tǒng)。 因此,cudaMemPoolTrimTo API 充當(dāng)空操作,并且 cudaMemPoolAttrReleaseThreshold 被有效地忽略。 此行為由驅(qū)動程序控制,而不是運行時控制,并且可能會在未來的驅(qū)動程序更新中發(fā)生變化。

F.11.5. IPC Import Pool Limitations

不允許從導(dǎo)入池中分配; 具體來說,導(dǎo)入池不能設(shè)置為當(dāng)前,也不能在 cudaMallocFromPoolAsync API 中使用。 因此,分配重用策略屬性對這些池沒有意義。

IPC 池目前不支持將物理塊釋放回操作系統(tǒng)。 因此,cudaMemPoolTrimTo API 充當(dāng)空操作,并且 cudaMemPoolAttrReleaseThreshold 被有效地忽略。

資源使用統(tǒng)計屬性查詢僅反映導(dǎo)入進(jìn)程的分配和相關(guān)的物理內(nèi)存。

F.12. Synchronization API Actions

作為 CUDA 驅(qū)動程序一部分的分配器帶來的優(yōu)化之一是與同步 API 的集成。 當(dāng)用戶請求 CUDA 驅(qū)動程序同步時,驅(qū)動程序等待異步工作完成。 在返回之前,驅(qū)動程序?qū)⒋_定什么釋放了保證完成的同步。 無論指定的流或禁用的分配策略如何,這些分配都可用于分配。 驅(qū)動程序還在這里檢查 cudaMemPoolAttrReleaseThreshold 并釋放它可以釋放的任何多余的物理內(nèi)存。

F.13. Addendums

F.13.1. cudaMemcpyAsync Current Context/Device Sensitivity

在當(dāng)前的 CUDA 驅(qū)動程序中,任何涉及來自 cudaMallocAsync 的內(nèi)存的異步 memcpy 都應(yīng)該使用指定流的上下文作為調(diào)用線程的當(dāng)前上下文來完成。 這對于 cudaMemcpyPeerAsync 不是必需的,因為引用了 API 中指定的設(shè)備主上下文而不是當(dāng)前上下文。

F.13.2. cuPointerGetAttribute Query

在對分配調(diào)用 cudaFreeAsync 后在分配上調(diào)用 cuPointerGetAttribute 會導(dǎo)致未定義的行為。 具體來說,分配是否仍然可以從給定的流中訪問并不重要:行為仍然是未定義的。

F.13.3. cuGraphAddMemsetNode

cuGraphAddMemsetNode 不適用于通過流排序分配器分配的內(nèi)存。 但是,分配的 memset 可以被流捕獲。

F.13.4. Pointer Attributes

cuPointerGetAttributes 查詢適用于流有序分配。 由于流排序分配與上下文無關(guān),因此查詢 CU_POINTER_ATTRIBUTE_CONTEXT 將成功,但在 *data 中返回 NULL。 屬性 CU_POINTER_ATTRIBUTE_DEVICE_ORDINAL 可用于確定分配的位置:這在選擇使用 cudaMemcpyPeerAsync 制作 p2h2p 拷貝的上下文時很有用。 CU_POINTER_ATTRIBUTE_MEMPOOL_HANDLE 屬性是在 CUDA 11.3 中添加的,可用于調(diào)試和在執(zhí)行 IPC 之前確認(rèn)分配來自哪個池。

關(guān)于作者

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

審核編輯:郭婷

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • gpu
    gpu
    +關(guān)注

    關(guān)注

    28

    文章

    4847

    瀏覽量

    129937
  • CUDA
    +關(guān)注

    關(guān)注

    0

    文章

    122

    瀏覽量

    13867
收藏 0人收藏

    評論

    相關(guān)推薦

    PS2-88,PS2-88/NF功率分配器MCLI

    PS2-88,PS2-88/NF功率分配器MCLIPS2-88功率分配器是MCLI品牌推出的一款高性能射頻微波器件,屬于PS2系列2路功率分配器。PS2-88功率分配器是一款高性能的射
    發(fā)表于 03-20 09:31

    PS2-185/NF帶狀線2路電源分配器

    ,PS2-185/NF帶狀線2路電源分配器的插入損耗較低,通常在1.2dB左右,這意味著信號通過分配器時的衰減較小。隔離度:隔離度是指分配器各輸出端口之間的信號隔離程度。PS2-18
    發(fā)表于 01-08 09:23

    英邁質(zhì)譜流路分配器:精準(zhǔn)控制,引領(lǐng)質(zhì)譜分析新高度

    質(zhì)譜分析這一精密科學(xué)領(lǐng)域,流體的精準(zhǔn)輸送對于獲取高質(zhì)量數(shù)據(jù)至關(guān)重要。為了滿足這一嚴(yán)苛需求,Instrumax(英邁儀器)憑借其流體控制領(lǐng)域的深厚積累,推出了全新的質(zhì)譜流路分配器。 這款質(zhì)譜流路
    的頭像 發(fā)表于 12-26 14:14 ?265次閱讀

    CDCL1810A 1.8V、10 輸出高性能時鐘分配器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《CDCL1810A 1.8V、10 輸出高性能時鐘分配器數(shù)據(jù)表.pdf》資料免費下載
    發(fā)表于 08-23 10:08 ?0次下載
    CDCL1810A 1.8V、10 輸出高性能時鐘<b class='flag-5'>分配器</b>數(shù)據(jù)表

    CDCL1810 1.8V 10路輸出高性能時鐘分配器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《CDCL1810 1.8V 10路輸出高性能時鐘分配器數(shù)據(jù)表.pdf》資料免費下載
    發(fā)表于 08-22 11:14 ?0次下載
    CDCL1810 1.8V 10路輸出高性能時鐘<b class='flag-5'>分配器</b>數(shù)據(jù)表

    CDCE18005高性能時鐘分配器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《CDCE18005高性能時鐘分配器數(shù)據(jù)表.pdf》資料免費下載
    發(fā)表于 08-21 11:12 ?0次下載
    CDCE18005高性能時鐘<b class='flag-5'>分配器</b>數(shù)據(jù)表

    CDCE62005高性能時鐘發(fā)生器和分配器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《CDCE62005高性能時鐘發(fā)生器和分配器數(shù)據(jù)表.pdf》資料免費下載
    發(fā)表于 08-21 11:12 ?0次下載
    CDCE62005高性能時鐘發(fā)生器和<b class='flag-5'>分配器</b>數(shù)據(jù)表

    LMK01000高性能時鐘緩沖器、分頻器和分配器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《LMK01000高性能時鐘緩沖器、分頻器和分配器數(shù)據(jù)表.pdf》資料免費下載
    發(fā)表于 08-21 09:53 ?0次下載
    LMK01000高性能時鐘緩沖器、分頻器和<b class='flag-5'>分配器</b>數(shù)據(jù)表

    液壓分配器起什么作用的

    液壓分配器是一種用于控制液壓系統(tǒng)中液體流量和壓力的設(shè)備。它在許多工業(yè)和工程應(yīng)用中發(fā)揮著重要作用,例如在液壓升降機(jī)、液壓挖掘機(jī)、液壓起重機(jī)等設(shè)備中。以下是液壓分配器的主要功能和原理: 流量控制 :液壓分配器
    的頭像 發(fā)表于 07-10 10:56 ?1469次閱讀

    液壓分配器工作原理是什么

    由閥體、閥芯、彈簧、密封件等組成。閥體是分配器的外殼,內(nèi)部有多個通道和孔口,用于連接液壓泵和執(zhí)行機(jī)構(gòu)。閥芯是分配器的核心部件,通過其閥體內(nèi)的運動,實現(xiàn)油液的分配和切換。彈簧用于提供閥
    的頭像 發(fā)表于 07-10 10:55 ?2899次閱讀

    液壓分配器壓力調(diào)整方法有哪些

    液壓分配器,又稱液壓分配器或液壓分流器,是一種用于液壓系統(tǒng)中的設(shè)備,主要用于將液壓系統(tǒng)中的壓力油分配到各個執(zhí)行元件,以實現(xiàn)對液壓系統(tǒng)的控制和調(diào)節(jié)。 一、液壓分配器壓力調(diào)整的重要性 液壓
    的頭像 發(fā)表于 07-10 10:53 ?2783次閱讀

    單線分配器與雙線分配器的區(qū)別是什么

    單線分配器與雙線分配器是兩種不同類型的電子設(shè)備,它們通信、廣播、電視等領(lǐng)域中有著廣泛的應(yīng)用。本文將介紹單線分配器與雙線分配器的區(qū)別。 一、
    的頭像 發(fā)表于 07-10 10:44 ?1350次閱讀

    四路數(shù)據(jù)分配器的基本概念、工作原理、應(yīng)用場景及設(shè)計方法

    四路數(shù)據(jù)分配器是一種數(shù)字電路元件,它的作用是將一個數(shù)據(jù)輸入信號分配成多個數(shù)據(jù)輸出信號。 1. 四路數(shù)據(jù)分配器的基本概念 四路數(shù)據(jù)分配器是一種多路復(fù)用器(Multiplexer),它將一
    的頭像 發(fā)表于 07-10 10:42 ?2426次閱讀

    八路數(shù)據(jù)分配器的基本概念及工作原理

    八路數(shù)據(jù)分配器是一種常見的電子設(shè)備,用于將一個輸入信號分配到多個輸出端。本文中,我們將詳細(xì)介紹八路數(shù)據(jù)分配器的基本概念、工作原理、應(yīng)用場景以及設(shè)計方法。 一、八路數(shù)據(jù)
    的頭像 發(fā)表于 07-10 10:40 ?2933次閱讀

    DS90LV110AT 1至10 LVDS數(shù)據(jù)/時鐘分配器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《DS90LV110AT 1至10 LVDS數(shù)據(jù)/時鐘分配器數(shù)據(jù)表.pdf》資料免費下載
    發(fā)表于 07-05 11:34 ?0次下載
    DS90LV110AT 1至10 LVDS數(shù)據(jù)/時鐘<b class='flag-5'>分配器</b>數(shù)據(jù)表
    主站蜘蛛池模板: 恋夜秀场1234手机视频在线观看 | aaaaaaa一级毛片 | 久久热这里只有 精品 | 国产国拍精品AV在线观看 | 三级黄.色 | 久久伊人中文字幕有码 | 国产亚洲va在线电影 | 噜噜噜狠狠夜夜躁精品 | 亚洲精品青青草原avav久久qv | 国产免费人视频在线观看免费 | 精品国产美女AV久久久久 | 久久9精品区-无套内射无码 | 肉动漫3D卡通无修在线播放 | 国产精品久久久久久久久LI无码 | 97国产在线播放 | 96.8在线收听 | 国产又湿又黄又硬又刺激视频 | 久久久久久久久久综合情日本 | 亚州日韩精品AV片无码中文 | 亚洲国产在线综合018 | 亚洲 中文 自拍 无码 | 成 人 片 免费播放 成 人 免费 黄 色 网站无毒下载 | 手机移动oa | 国产精品野外AV久久久 | 免费三级黄色 | 亚洲精品有码在线观看 | 伊人青青草 | 99久久久国产精品免费蜜臀 | 伦理片a在线线2 | 亚洲精品成人无码区一在线观看 | 99精品国产免费久久久久久下载 | 九色PORNY丨视频入口 | 国产扒开美女双腿屁股流白浆 | 中文字幕AV在线一二三区 | 花蝴蝶在线高清视频观看免费播放 | 最新国产成人综合在线观看 | 日本19xxxx撤尿| bbwxxxx交女警 | 欧美熟妇互舔20p | 69xx欧美 | 果冻传媒2021一二三在线观看 |

    電子發(fā)燒友

    中國電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會員交流學(xué)習(xí)
    • 獲取您個性化的科技前沿技術(shù)信息
    • 參加活動獲取豐厚的禮品