欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

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

對(duì)于許多應(yīng)用程序,Stream Ordered Memory Allocator 減少了對(duì)自定義內(nèi)存管理抽象的需求,并使為需要它的應(yīng)用程序創(chuàng)建高性能自定義內(nèi)存管理變得更加容易。對(duì)于已經(jīng)具有自定義內(nèi)存分配器的應(yīng)用程序和庫,采用 Stream Ordered Memory Allocator 可以使多個(gè)庫共享由驅(qū)動(dòng)程序管理的公共內(nèi)存池,從而減少過多的內(nèi)存消耗。此外,驅(qū)動(dòng)程序可以根據(jù)其對(duì)分配器和其他流管理 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ū)動(dòng)程序?qū)⒎祷?cudaErrorInvalidValue,因?yàn)檫@些驅(qū)動(dòng)程序不知道屬性枚舉。

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ū)動(dòng)程序版本檢查可避免在尚未定義屬性的驅(qū)動(dòng)程序上遇到 cudaErrorInvalidValue 錯(cuò)誤。 可以使用 cudaGetLastError 來清除錯(cuò)誤而不是避免它。

F.3. API Fundamentals (cudaMallocAsync and cudaFreeAsync)

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

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)存。 在自由操作開始之前,用戶必須對(duì)訪問完成做出同樣的保證。

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

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

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)存的種類和位置。

所有對(duì) 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í)將它們稱為隱式池。 設(shè)備默認(rèn)內(nèi)存池不支持IPC。

F.6. Explicit Pools

API cudaMemPoolCreate 創(chuàng)建一個(gè)顯式池。 目前內(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)用程序必須為每個(gè)池配置內(nèi)存占用。 應(yīng)用程序可以使用釋放閾值屬性 (cudaMemPoolAttrReleaseThreshold) 執(zhí)行此操作。

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

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

cudaMemPoolAttrReleaseThreshold設(shè)置得足夠高以有效禁用內(nèi)存池收縮的應(yīng)用程序可能希望顯式收縮內(nèi)存池的內(nèi)存占用。cudaMemPoolTrimTo允許此類應(yīng)用程序這樣做。 在修剪內(nèi)存池的占用空間時(shí),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 屬性會(huì)報(bào)告該池當(dāng)前消耗的總物理 GPU 內(nèi)存。 查詢池的 cudaMemPoolAttrUsedMemCurrent 會(huì)返回從池中分配且不可重用的所有內(nèi)存的總大小。

cudaMemPoolAttr*MemHigh 屬性是記錄自上次重置以來各個(gè) 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ǐng)求,驅(qū)動(dòng)程序在嘗試從操作系統(tǒng)分配更多內(nèi)存之前嘗試重用之前通過 cudaFreeAsync() 釋放的內(nèi)存。 例如,流中釋放的內(nèi)存可以立即重新用于同一流中的后續(xù)分配請(qǐng)求。 類似地,當(dāng)一個(gè)流與 CPU 同步時(shí),之前在該流中釋放的內(nèi)存可以重新用于任何流中的分配。

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

F.9.1. cudaMemPoolReuseFollowEventDependencies

在分配更多物理 GPU 內(nèi)存之前,分配器會(huì)檢查由 CUDA 事件建立的依賴信息,并嘗試從另一個(gè)流中釋放的內(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í)行點(diǎn))。 禁用此功能后,分配器仍將重用在流與 cpu 同步時(shí)可用的內(nèi)存。 禁用此策略不會(huì)阻止 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ū)動(dòng)程序?qū)ふ移淇捎眯匀Q于另一個(gè)流的待處理進(jìn)度的內(nèi)存。 如果找到這樣的內(nèi)存,驅(qū)動(dòng)程序會(huì)將所需的依賴項(xiàng)插入分配流并重用內(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ī)會(huì)重用(即 cudaMemPoolReuseAllowOpportunistic)基于 CPU 和 GPU 執(zhí)行的交錯(cuò)引入了運(yùn)行到運(yùn)行分配模式的差異。 當(dāng)用戶寧愿在分配失敗時(shí)顯式同步事件或流時(shí),內(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è)備對(duì)等;檢查 cudaDeviceCanAccessPeer。如果未檢查對(duì)等功能,則設(shè)置訪問可能會(huì)失敗并顯示 cudaErrorInvalidDevice。如果沒有從池中進(jìn)行分配,即使設(shè)備不具備對(duì)等能力,cudaMemPoolSetAccess 調(diào)用也可能成功;在這種情況下,池中的下一次分配將失敗。

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

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

F.11.1. Creating and Sharing IPC Memory Pools

共享對(duì)池的訪問涉及檢索池的 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)中指定的請(qǐng)求句柄類型創(chuàng)建內(nèi)存池。 請(qǐng)參考示例以了解在進(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)入過程需要啟用從它計(jì)劃訪問內(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)程共享。由于池的安全策略是在池級(jí)別建立和驗(yàn)證的,操作系統(tǒng)不需要額外的簿記來為特定的池分配提供安全性;換句話說,導(dǎo)入池分配所需的不透明 cudaMemPoolPtrExportData 可以使用任何機(jī)制發(fā)送到導(dǎo)入進(jìn)程。

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

// 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, ...);

釋放分配時(shí),需要先在導(dǎo)入過程中釋放分配,然后在導(dǎo)出過程中釋放分配。 以下代碼片段演示了使用 CUDA IPC 事件在兩個(gè)進(jìn)程中的cudaFreeAsync操作之間提供所需的同步。 導(dǎo)入過程中對(duì)分配的訪問顯然受到導(dǎo)入過程側(cè)的自由操作的限制。 值得注意的是,cudaFree可用于釋放兩個(gè)進(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ū)動(dòng)程序控制,而不是運(yùn)行時(shí)控制,并且可能會(huì)在未來的驅(qū)動(dòng)程序更新中發(fā)生變化。

F.11.5. IPC Import Pool Limitations

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

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

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

F.12. Synchronization API Actions

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

F.13. Addendums

F.13.1. cudaMemcpyAsync Current Context/Device Sensitivity

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

F.13.2. cuPointerGetAttribute Query

在對(duì)分配調(diào)用 cudaFreeAsync 后在分配上調(diào)用 cuPointerGetAttribute 會(huì)導(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 拷貝的上下文時(shí)很有用。 CU_POINTER_ATTRIBUTE_MEMPOOL_HANDLE 屬性是在 CUDA 11.3 中添加的,可用于調(diào)試和在執(zhí)行 IPC 之前確認(rèn)分配來自哪個(gè)池。

關(guān)于作者

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

審核編輯:郭婷

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

    關(guān)注

    28

    文章

    4787

    瀏覽量

    129415
  • CUDA
    +關(guān)注

    關(guān)注

    0

    文章

    121

    瀏覽量

    13698
收藏 人收藏

    評(píng)論

    相關(guān)推薦

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    液壓分配器起什么作用的

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

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

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

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

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

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

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

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

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

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

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

    Linux內(nèi)核內(nèi)存管理之slab分配器

    本文在行文的過程中,會(huì)多次提到cache或緩存的概念。如果沒有特殊在前面添加硬件的限定詞,就說明cache指的是slab分配器使用的軟件緩存的意思。如果添加了硬件限定詞,則指的是處理器的硬件緩存,比如L1-DCache、L1-ICache之類的。
    的頭像 發(fā)表于 02-22 09:25 ?1364次閱讀
    Linux內(nèi)核內(nèi)存管理之slab<b class='flag-5'>分配器</b>

    Linux內(nèi)核內(nèi)存管理之ZONE內(nèi)存分配器

    內(nèi)核中使用ZONE分配器滿足內(nèi)存分配請(qǐng)求。該分配器必須具有足夠的空閑頁幀,以便滿足各種內(nèi)存大小請(qǐng)求。
    的頭像 發(fā)表于 02-21 09:29 ?959次閱讀