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

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

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

3天內不再提示

允許圖創建和擁有內存分配功能的圖內存節點

星星科技指導員 ? 來源:NVIDIA ? 作者:Ken He ? 2022-04-28 09:59 ? 次閱讀

G.1. Introduction

圖內存節點允許圖創建和擁有內存分配功能。圖內存節點具有 GPU 有序生命周期語義,它指示何時允許在設備上訪問內存。這些 GPU 有序生命周期語義支持驅動程序管理的內存重用,并與流序分配 API cudaMallocAsync 和 cudaFreeAsync 相匹配,這可能在創建圖形時被捕獲。

圖分配在圖的生命周期內具有固定的地址,包括重復的實例化和啟動。這允許圖中的其他操作直接引用內存,而無需更新圖,即使 CUDA 更改了后備物理內存也是如此。在一個圖中,其圖有序生命周期不重疊的分配可以使用相同的底層物理內存。

CUDA 可以重用相同的物理內存進行跨多個圖的分配,根據 GPU 有序生命周期語義對虛擬地址映射進行別名化。例如,當不同的圖被啟動到同一個流中時,CUDA 可以虛擬地為相同的物理內存取別名,以滿足具有單圖生命周期的分配的需求。

G.2. Support and Compatibility

圖內存節點需要支持 11.4 的 CUDA 驅動程序并支持 GPU 上的流序分配器。 以下代碼段顯示了如何檢查給定設備上的支持。

int driverVersion = 0;
int deviceSupportsMemoryPools = 0;
int deviceSupportsMemoryNodes = 0;
cudaDriverGetVersion(&driverVersion);
if (driverVersion >= 11020) { // avoid invalid value error in cudaDeviceGetAttribute
    cudaDeviceGetAttribute(&deviceSupportsMemoryPools, cudaDevAttrMemoryPoolsSupported, device);
}
deviceSupportsMemoryNodes = (driverVersion >= 11040) && (deviceSupportsMemoryPools != 0);

在驅動程序版本檢查中執行屬性查詢可避免 11.0 和 11.1 驅動程序上的無效值返回代碼。 請注意,計算清理程序在檢測到 CUDA 返回錯誤代碼時會發出警告,并且在讀取屬性之前進行版本檢查將避免這種情況。 圖形內存節點僅在驅動程序版本 11.4 和更高版本上受支持。

G.3. API Fundamentals

圖內存節點是表示內存分配或空閑操作的圖節點。 簡而言之,分配內存的節點稱為分配節點。 同樣,釋放內存的節點稱為空閑節點。 分配節點創建的分配稱為圖分配。 CUDA 在節點創建時為圖分配分配虛擬地址。 雖然這些虛擬地址在分配節點的生命周期內是固定的,但分配內容在釋放操作之后不會持久,并且可能被引用不同分配的訪問覆蓋。

每次圖運行時,圖分配都被視為重新創建。 圖分配的生命周期與節點的生命周期不同,從 GPU 執行到達分配圖節點時開始,并在發生以下情況之一時結束:

GPU 執行到達釋放圖節點

GPU 執行到達釋放 cudaFreeAsync() 流調用

立即釋放對 cudaFree() 的調用

注意:圖銷毀不會自動釋放任何實時圖分配的內存,即使它結束了分配節點的生命周期。 隨后必須在另一個圖中或使用 cudaFreeAsync()/cudaFree() 釋放分配。

就像其他圖節點一樣,圖內存節點在圖中按依賴邊排序。 程序必須保證訪問圖內存的操作:

在分配節點之后排序。

在釋放內存的操作之前排序

圖分配生命周期根據 GPU 執行開始和結束(與 API 調用相反)。 GPU 排序是工作在 GPU 上運行的順序,而不是工作隊列或描述的順序。 因此,圖分配被認為是“GPU 有序”。

G.3.1. Graph Node APIs

可以使用內存節點創建 API、cudaGraphAddMemAllocNode 和 cudaGraphAddMemFreeNode 顯式創建圖形內存節點。 cudaGraphAddMemAllocNode 分配的地址在傳遞的 CUDA_MEM_ALLOC_NODE_PARAMS 結構的 dptr 字段中返回給用戶。 在分配圖中使用圖分配的所有操作必須在分配節點之后排序。 類似地,任何空閑節點都必須在圖中所有分配的使用之后進行排序。 cudaGraphAddMemFreeNode 創建空閑節點。

在下圖中,有一個帶有分配和空閑節點的示例圖。 內核節點 a、b 和 c 在分配節點之后和空閑節點之前排序,以便內核可以訪問分配。 內核節點 e 沒有排在 alloc 節點之后,因此無法安全地訪問內存。 內核節點 d 沒有排在空閑節點之前,因此它不能安全地訪問內存。

以下代碼片段建立了該圖中的圖:

// Create the graph - it starts out empty
cudaGraphCreate(&graph, 0);

// parameters for a basic allocation
cudaMemAllocNodeParams params = {};
params.poolProps.allocType = cudaMemAllocationTypePinned;
params.poolProps.location.type = cudaMemLocationTypeDevice;
// specify device 0 as the resident device
params.poolProps.location.id = 0;
params.bytesize = size;

cudaGraphAddMemAllocNode(&allocNode, graph, NULL, 0, ¶ms);
nodeParams->kernelParams[0] = params.dptr;
cudaGraphAddKernelNode(&a, graph, &allocNode, 1, &nodeParams);
cudaGraphAddKernelNode(&b, graph, &a, 1, &nodeParams);
cudaGraphAddKernelNode(&c, graph, &a, 1, &nodeParams);
cudaGraphNode_t dependencies[2];
// kernel nodes b and c are using the graph allocation, so the freeing node must depend on them.  Since the dependency of node b on node a establishes an indirect dependency, the free node does not need to explicitly depend on node a.
dependencies[0] = b;
dependencies[1] = c;
cudaGraphAddMemFreeNode(&freeNode, graph, dependencies, 2, params.dptr);
// free node does not depend on kernel node d, so it must not access the freed graph allocation.
cudaGraphAddKernelNode(&d, graph, &c, 1, &nodeParams);

// node e does not depend on the allocation node, so it must not access the allocation.  This would be true even if the freeNode depended on kernel node e.
cudaGraphAddKernelNode(&e, graph, NULL, 0, &nodeParams);

G.3.2. Stream Capture

可以通過捕獲相應的流序分配和免費調用 cudaMallocAsync 和 cudaFreeAsync 來創建圖形內存節點。 在這種情況下,捕獲的分配 API 返回的虛擬地址可以被圖中的其他操作使用。 由于流序的依賴關系將被捕獲到圖中,流序分配 API 的排序要求保證了圖內存節點將根據捕獲的流操作正確排序(對于正確編寫的流代碼)。

忽略內核節點 d 和 e,為清楚起見,以下代碼片段顯示了如何使用流捕獲來創建上圖中的圖形:

cudaMallocAsync(&dptr, size, stream1);
kernel_A<<< ..., stream1 >>>(dptr, ...);

// Fork into stream2
cudaEventRecord(event1, stream1);
cudaStreamWaitEvent(stream2, event1);

kernel_B<<< ..., stream1 >>>(dptr, ...);
// event dependencies translated into graph dependencies, so the kernel node created by the capture of kernel C will depend on the allocation node created by capturing the cudaMallocAsync call. 
kernel_C<<< ..., stream2 >>>(dptr, ...);

// Join stream2 back to origin stream (stream1)
cudaEventRecord(event2, stream2);
cudaStreamWaitEvent(stream1, event2);

// Free depends on all work accessing the memory.
cudaFreeAsync(dptr, stream1);

// End capture in the origin stream
cudaStreamEndCapture(stream1, &graph);

G.3.3. Accessing and Freeing Graph Memory Outside of the Allocating Graph

圖分配不必由分配圖釋放。當圖不釋放分配時,該分配會在圖執行之后持續存在,并且可以通過后續 CUDA 操作訪問。這些分配可以在另一個圖中訪問或直接通過流操作訪問,只要訪問操作在分配之后通過 CUDA 事件和其他流排序機制進行排序。隨后可以通過定期調用 cudaFree、cudaFreeAsync 或通過啟動具有相應空閑節點的另一個圖,或隨后啟動分配圖(如果它是使用 cudaGraphInstantiateFlagAutoFreeOnLaunch 標志實例化)來釋放分配。在內存被釋放后訪問內存是非法的 – 必須在所有使用圖依賴、CUDA 事件和其他流排序機制訪問內存的操作之后對釋放操作進行排序。

注意:因為圖分配可能彼此共享底層物理內存,所以必須考慮與一致性和一致性相關的虛擬混疊支持規則。簡單地說,空閑操作必須在完整的設備操作(例如,計算內核/ memcpy)完成后排序。具體來說,帶外同步——例如,作為訪問圖形內存的計算內核的一部分,通過內存進行信號交換——不足以提供對圖形內存的寫操作和該圖形內存的自由操作之間的排序保證。

以下代碼片段演示了在分配圖之外訪問圖分配,并通過以下方式正確建立順序:使用單個流,使用流之間的事件,以及使用嵌入到分配和釋放圖中的事件。

使用單個流建立的排序:

void *dptr;
cudaGraphAddMemAllocNode(&allocNode, allocGraph, NULL, 0, ¶ms);
dptr = params.dptr;

cudaGraphInstantiate(&allocGraphExec, allocGraph, NULL, NULL, 0);

cudaGraphLaunch(allocGraphExec, stream);
kernel<<< …, stream >>>(dptr, …);
cudaFreeAsync(dptr, stream);

通過記錄和等待 CUDA 事件建立的排序:

void *dptr;

// Contents of allocating graph
cudaGraphAddMemAllocNode(&allocNode, allocGraph, NULL, 0, ¶ms);
dptr = params.dptr;

// contents of consuming/freeing graph
nodeParams->kernelParams[0] = params.dptr;
cudaGraphAddKernelNode(&a, graph, NULL, 0, &nodeParams);
cudaGraphAddMemFreeNode(&freeNode, freeGraph, &a, 1, dptr);

cudaGraphInstantiate(&allocGraphExec, allocGraph, NULL, NULL, 0);
cudaGraphInstantiate(&freeGraphExec, freeGraph, NULL, NULL, 0);

cudaGraphLaunch(allocGraphExec, allocStream);

// establish the dependency of stream2 on the allocation node
// note: the dependency could also have been established with a stream synchronize operation
cudaEventRecord(allocEvent, allocStream)
cudaStreamWaitEvent(stream2, allocEvent);

kernel<<< …, stream2 >>> (dptr, …);

// establish the dependency between the stream 3 and the allocation use
cudaStreamRecordEvent(streamUseDoneEvent, stream2);
cudaStreamWaitEvent(stream3, streamUseDoneEvent);

// it is now safe to launch the freeing graph, which may also access the memory
cudaGraphLaunch(freeGraphExec, stream3);

使用圖外部事件節點建立的排序:

void *dptr;
cudaEvent_t allocEvent; // event indicating when the allocation will be ready for use.
cudaEvent_t streamUseDoneEvent; // event indicating when the stream operations are done with the allocation.

// Contents of allocating graph with event record node
cudaGraphAddMemAllocNode(&allocNode, allocGraph, NULL, 0, ¶ms);
dptr = params.dptr;
// note: this event record node depends on the alloc node
cudaGraphAddEventRecordNode(&recordNode, allocGraph, &allocNode, 1, allocEvent);
cudaGraphInstantiate(&allocGraphExec, allocGraph, NULL, NULL, 0);

// contents of consuming/freeing graph with event wait nodes
cudaGraphAddEventWaitNode(&streamUseDoneEventNode, waitAndFreeGraph, NULL, 0, streamUseDoneEvent);
cudaGraphAddEventWaitNode(&allocReadyEventNode, waitAndFreeGraph, NULL, 0, allocEvent);
nodeParams->kernelParams[0] = params.dptr;

// The allocReadyEventNode provides ordering with the alloc node for use in a consuming graph.
cudaGraphAddKernelNode(&kernelNode, waitAndFreeGraph, &allocReadyEventNode, 1, &nodeParams);

// The free node has to be ordered after both external and internal users.
// Thus the node must depend on both the kernelNode and the 
// streamUseDoneEventNode.
dependencies[0] = kernelNode;
dependencies[1] = streamUseDoneEventNode;
cudaGraphAddMemFreeNode(&freeNode, waitAndFreeGraph, &dependencies, 2, dptr);
cudaGraphInstantiate(&waitAndFreeGraphExec, waitAndFreeGraph, NULL, NULL, 0);

cudaGraphLaunch(allocGraphExec, allocStream);

// establish the dependency of stream2 on the event node satisfies the ordering requirement
cudaStreamWaitEvent(stream2, allocEvent);
kernel<<< …, stream2 >>> (dptr, …);
cudaStreamRecordEvent(streamUseDoneEvent, stream2);

// the event wait node in the waitAndFreeGraphExec establishes the dependency on the “readyForFreeEvent” that is needed to prevent the kernel running in stream two from accessing the allocation after the free node in execution order.
cudaGraphLaunch(waitAndFreeGraphExec, stream3);

G.3.4. cudaGraphInstantiateFlagAutoFreeOnLaunch

在正常情況下,如果圖有未釋放的內存分配,CUDA 將阻止重新啟動圖,因為同一地址的多個分配會泄漏內存。使用 cudaGraphInstantiateFlagAutoFreeOnLaunch 標志實例化圖允許圖在其仍有未釋放的分配時重新啟動。在這種情況下,啟動會自動插入一個異步釋放的未釋放分配。

啟動時自動對于單生產者多消費者算法很有用。在每次迭代中,生產者圖創建多個分配,并且根據運行時條件,一組不同的消費者訪問這些分配。這種類型的變量執行序列意味著消費者無法釋放分配,因為后續消費者可能需要訪問。啟動時自動釋放意味著啟動循環不需要跟蹤生產者的分配 – 相反,該信息與生產者的創建和銷毀邏輯保持隔離。通常,啟動時自動釋放簡化了算法,否則該算法需要在每次重新啟動之前釋放圖所擁有的所有分配。

注意: cudaGraphInstantiateFlagAutoFreeOnLaunch 標志不會改變圖銷毀的行為。應用程序必須顯式釋放未釋放的內存以避免內存泄漏,即使對于使用標志實例化的圖也是如此。

以下代碼展示了使用 cudaGraphInstantiateFlagAutoFreeOnLaunch 來簡化單生產者/多消費者算法:

// Create producer graph which allocates memory and populates it with data
cudaStreamBeginCapture(cudaStreamPerThread, cudaStreamCaptureModeGlobal);
cudaMallocAsync(&data1, blocks * threads, cudaStreamPerThread);
cudaMallocAsync(&data2, blocks * threads, cudaStreamPerThread);
produce<<>>(data1, data2);
...
cudaStreamEndCapture(cudaStreamPerThread, &graph);
cudaGraphInstantiateWithFlags(&producer,
                              graph,
                              cudaGraphInstantiateFlagAutoFreeOnLaunch);
cudaGraphDestroy(graph);

// Create first consumer graph by capturing an asynchronous library call
cudaStreamBeginCapture(cudaStreamPerThread, cudaStreamCaptureModeGlobal);
consumerFromLibrary(data1, cudaStreamPerThread);
cudaStreamEndCapture(cudaStreamPerThread, &graph);
cudaGraphInstantiateWithFlags(&consumer1, graph, 0); //regular instantiation
cudaGraphDestroy(graph);

// Create second consumer graph
cudaStreamBeginCapture(cudaStreamPerThread, cudaStreamCaptureModeGlobal);
consume2<<>>(data2);
...
cudaStreamEndCapture(cudaStreamPerThread, &graph);
cudaGraphInstantiateWithFlags(&consumer2, graph, 0);
cudaGraphDestroy(graph);

// Launch in a loop
bool launchConsumer2 = false;
do {
    cudaGraphLaunch(producer, myStream);
    cudaGraphLaunch(consumer1, myStream);
    if (launchConsumer2) {
        cudaGraphLaunch(consumer2, myStream);
    }
} while (determineAction(&launchConsumer2));

cudaFreeAsync(data1, myStream);
cudaFreeAsync(data2, myStream);

cudaGraphExecDestroy(producer);
cudaGraphExecDestroy(consumer1);
cudaGraphExecDestroy(consumer2);

G.4. Optimized Memory Reuse

CUDA 以兩種方式重用內存:

圖中的虛擬和物理內存重用基于虛擬地址分配,就像在流序分配器中一樣。

圖之間的物理內存重用是通過虛擬別名完成的:不同的圖可以將相同的物理內存映射到它們唯一的虛擬地址。

G.4.1. Address Reuse within a Graph

CUDA 可以通過將相同的虛擬地址范圍分配給生命周期不重疊的不同分配來重用圖中的內存。 由于可以重用虛擬地址,因此不能保證指向具有不相交生命周期的不同分配的指針是唯一的。

下圖顯示了添加一個新的分配節點 (2),它可以重用依賴節點 (1) 釋放的地址。

下圖顯示了添加新的 alloc 節點(3)。 新的分配節點不依賴于空閑節點 (2),因此不能重用來自關聯分配節點 (2) 的地址。 如果分配節點 (2) 使用由空閑節點 (1) 釋放的地址,則新分配節點 3 將需要一個新地址。

G.4.2. Physical Memory Management and Sharing

CUDA 負責在按 GPU 順序到達分配節點之前將物理內存映射到虛擬地址。作為內存占用和映射開銷的優化,如果多個圖不會同時運行,它們可能會使用相同的物理內存進行不同的分配,但是如果它們同時綁定到多個執行圖,則物理頁面不能被重用,或未釋放的圖形分配。

CUDA 可以在圖形實例化、啟動或執行期間隨時更新物理內存映射。 CUDA 還可以在未來的圖啟動之間引入同步,以防止實時圖分配引用相同的物理內存。對于任何 allocate-free-allocate 模式,如果程序在分配的生命周期之外訪問指針,錯誤的訪問可能會默默地讀取或寫入另一個分配擁有的實時數據(即使分配的虛擬地址是唯一的)。使用計算清理工具可以捕獲此錯誤。

下圖顯示了在同一流中按順序啟動的圖形。在此示例中,每個圖都會釋放它分配的所有內存。由于同一流中的圖永遠不會同時運行,CUDA 可以而且應該使用相同的物理內存來滿足所有分配。

G.5. Performance Considerations

當多個圖啟動到同一個流中時,CUDA 會嘗試為它們分配相同的物理內存,因為這些圖的執行不能重疊。 在啟動之間保留圖形的物理映射作為優化以避免重新映射的成本。 如果稍后啟動其中一個圖,使其執行可能與其他圖重疊(例如,如果它啟動到不同的流中),則 CUDA 必須執行一些重新映射,因為并發圖需要不同的內存以避免數據損壞 。

一般來說,CUDA中圖內存的重新映射很可能是由這些操作引起的

更改啟動圖形的流

圖內存池上的修剪操作,顯式釋放未使用的內存(在物理內存占用中討論)

當另一個圖的未釋放分配映射到同一內存時重新啟動一個圖將導致在重新啟動之前重新映射內存

重新映射必須按執行順序發生,但在該圖的任何先前執行完成之后(否則可能會取消映射仍在使用的內存)。 由于這種排序依賴性,以及映射操作是操作系統調用,映射操作可能相對昂貴。 應用程序可以通過將包含分配內存節點的圖一致地啟動到同一流中來避免這種成本。

G.5.1. First Launch / cudaGraphUpload

在圖實例化期間無法分配或映射物理內存,因為圖將在其中執行的流是未知的。 映射是在圖形啟動期間完成的。 調用 cudaGraphUpload 可以通過立即執行該圖的所有映射并將該圖與上傳流相關聯,將分配成本與啟動分開。 如果圖隨后啟動到同一流中,它將啟動而無需任何額外的重新映射。

使用不同的流進行圖上傳和圖啟動的行為類似于切換流,可能會導致重新映射操作。 此外,允許無關的內存池管理從空閑流中提取內存,這可能會抵消上傳的影響。

G.6. Physical Memory Footprint

異步分配的池管理行為意味著銷毀包含內存節點的圖(即使它們的分配是空閑的)不會立即將物理內存返回給操作系統以供其他進程使用。要顯式將內存釋放回操作系統,應用程序應使用 cudaDeviceGraphMemTrim API。

cudaDeviceGraphMemTrim 將取消映射并釋放由圖形內存節點保留的未主動使用的任何物理內存。尚未釋放的分配和計劃或運行的圖被認為正在積極使用物理內存,不會受到影響。使用修剪 API 將使物理內存可用于其他分配 API 和其他應用程序或進程,但會導致 CUDA 在下次啟動修剪圖時重新分配和重新映射內存。請注意,cudaDeviceGraphMemTrim 在與 cudaMemPoolTrimTo() 不同的池上運行。圖形內存池不會暴露給流序內存分配器。 CUDA 允許應用程序通過 cudaDeviceGetGraphMemAttribute API 查詢其圖形內存占用量。查詢屬性 cudaGraphMemAttrReservedMemCurrent 返回驅動程序為當前進程中的圖形分配保留的物理內存量。查詢 cudaGraphMemAttrUsedMemCurrent 返回至少一個圖當前映射的物理內存量。這些屬性中的任何一個都可用于跟蹤 CUDA 何時為分配圖而獲取新的物理內存。這兩個屬性對于檢查共享機制節省了多少內存都很有用。

G.7. Peer Access

圖分配可以配置為從多個 GPU 訪問,在這種情況下,CUDA 將根據需要將分配映射到對等 GPU。 CUDA 允許需要不同映射的圖分配重用相同的虛擬地址。 發生這種情況時,地址范圍將映射到不同分配所需的所有 GPU。 這意味著分配有時可能允許比其創建期間請求的更多對等訪問; 然而,依賴這些額外的映射仍然是一個錯誤。

G.7.1. Peer Access with Graph Node APIs

cudaGraphAddMemAllocNode API 接受節點參數結構的 accessDescs 數組字段中的映射請求。 poolProps.location 嵌入式結構指定分配的常駐設備。 假設需要來自分配 GPU 的訪問,因此應用程序不需要在 accessDescs 數組中為常駐設備指定條目。

cudaMemAllocNodeParams params = {};
params.poolProps.allocType = cudaMemAllocationTypePinned;
params.poolProps.location.type = cudaMemLocationTypeDevice;
// specify device 1 as the resident device
params.poolProps.location.id = 1;
params.bytesize = size;

// allocate an allocation resident on device 1 accessible from device 1
cudaGraphAddMemAllocNode(&allocNode, graph, NULL, 0, ¶ms);

accessDescs[2];
// boilerplate for the access descs (only ReadWrite and Device access supported by the add node api)
accessDescs[0].flags = cudaMemAccessFlagsProtReadWrite;
accessDescs[0].location.type = cudaMemLocationTypeDevice;
accessDescs[1].flags = cudaMemAccessFlagsProtReadWrite;
accessDescs[1].location.type = cudaMemLocationTypeDevice;

// access being requested for device 0 & 2.  Device 1 access requirement left implicit.
accessDescs[0].location.id = 0;
accessDescs[1].location.id = 2;

// access request array has 2 entries.
params.accessDescCount = 2;
params.accessDescs = accessDescs;

// allocate an allocation resident on device 1 accessible from devices 0, 1 and 2. (0 & 2 from the descriptors, 1 from it being the resident device).
cudaGraphAddMemAllocNode(&allocNode, graph, NULL, 0, ¶ms);

G.7.2. Peer Access with Stream Capture

對于流捕獲,分配節點在捕獲時記錄分配池的對等可訪問性。 在捕獲 cudaMallocFromPoolAsync 調用后更改分配池的對等可訪問性不會影響圖將為分配進行的映射。

// boilerplate for the access descs (only ReadWrite and Device access supported by the add node api)
accessDesc.flags = cudaMemAccessFlagsProtReadWrite;
accessDesc.location.type = cudaMemLocationTypeDevice;
accessDesc.location.id = 1;

// let memPool be resident and accessible on device 0

cudaStreamBeginCapture(stream);
cudaMallocAsync(&dptr1, size, memPool, stream);
cudaStreamEndCapture(stream, &graph1);

cudaMemPoolSetAccess(memPool, &accessDesc, 1);

cudaStreamBeginCapture(stream);
cudaMallocAsync(&dptr2, size, memPool, stream);
cudaStreamEndCapture(stream, &graph2);

//The graph node allocating dptr1 would only have the device 0 accessibility even though memPool now has device 1 accessibility.
//The graph node allocating dptr2 will have device 0 and device 1 accessibility, since that was the pool accessibility at the time of the cudaMallocAsync call.

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

    關注

    28

    文章

    4752

    瀏覽量

    129057
  • API
    API
    +關注

    關注

    2

    文章

    1504

    瀏覽量

    62162
  • CUDA
    +關注

    關注

    0

    文章

    121

    瀏覽量

    13642
收藏 人收藏

    評論

    相關推薦

    Linux下如何管理虛擬內存 使用虛擬內存時的常見問題

    在Linux系統中,虛擬內存管理是操作系統內核的一個重要功能,負責管理物理內存和磁盤上的交換空間。以下是對Linux下如何管理虛擬內存以及使用虛擬
    的頭像 發表于 12-04 09:19 ?478次閱讀

    什么是虛擬內存分頁 Windows系統虛擬內存優化方法

    虛擬內存分頁概述 在Windows操作系統中,虛擬內存是通過分頁機制實現的。分頁允許系統將內存中的數據移動到硬盤上,以便為當前運行的程序騰出空間。這個過程對于保持系統的流暢運行至關重要
    的頭像 發表于 12-04 09:16 ?403次閱讀

    虛擬內存的作用和原理 如何調整虛擬內存設置

    虛擬內存,也稱為虛擬內存管理或頁面文件,是計算機操作系統中的一種內存管理技術。它允許系統使用硬盤空間作為額外的RAM(隨機存取存儲器),以彌補物理
    的頭像 發表于 12-04 09:13 ?513次閱讀

    內存模組n/a怎么解決?

    一、內存模組n/a問題概述 1.1 內存模組的定義 內存模組,又稱為RAM(Random Access Memory),是計算機系統中用于存儲數據的硬件設備。它允許處理器快速訪問和處理
    的頭像 發表于 10-14 10:44 ?682次閱讀

    TH反射內存交換機使用手冊

    一、反射內存交換機概述反射內存交換機是為特定的反射內存網絡而設計的設備,它可以自動旁路故障節點允許網絡中的其他
    的頭像 發表于 09-05 17:16 ?403次閱讀
    TH反射<b class='flag-5'>內存</b>交換機使用手冊

    轉載 golang內存分配

    . 線程擁有一定的 cache, 可用于無鎖分配. 同時 Go 對于 GC 后回收的內存頁, 并不是馬上歸還給操作系統, 而是會延遲歸還, 用于滿足未來的內存需求. ?? ? 在 1.
    的頭像 發表于 09-05 14:12 ?279次閱讀
    轉載 golang<b class='flag-5'>內存</b><b class='flag-5'>分配</b>

    反射內存卡原理說明

    一、引言反射內存卡是一種用于實現高速數據共享和實時通信的先進技術。它在多個領域,特別是對數據傳輸速度和實時性要求極高的應用中,發揮著關鍵作用。二、基本原理共享內存模型反射內存創建了一
    的頭像 發表于 09-04 10:19 ?343次閱讀
    反射<b class='flag-5'>內存</b>卡原理說明

    如何自定義內存控制器的設置

    策略都有其特定的使用場景和優缺點。以下是一些步驟和建議,用于自定義內存控制器的設置: 1. 選擇合適的內存分配策略 heap_1 :最簡單的內存分配
    的頭像 發表于 09-02 14:28 ?521次閱讀

    ESP32S3+LVGL創建一個界面,請問能只在SPIRAM分配內存,IRAM不分配嗎?

    各位前輩好。ESP32S3+LVGL的開發的過程中發現,創建一個界面,會同時在SPIRAM和IRAM分配相同大小的內存。請問能只在SPIRAM分配
    發表于 06-06 07:45

    FreeRTOS如何在中斷中調用內存分配函數?

    最近在玩FreeRTOS,遇到一個問題,就是不知如何在中斷中調用內存分配函數。pvPortMalloc函數中會調用xTaskResumeAll,而這個函數不能再中斷調用,所以請問在中斷中進行內存
    發表于 05-08 08:25

    freertos任務創建,每一個任務分配內存是多大才好,怎么計算呢?

    小白剛剛接觸freertos,想問一下就創建任務而言,每一個任務分配內存是多大才好,怎么計算呢? 另外,每個任務的執行周期怎么確定?在任務里面放延時函數嗎?
    發表于 04-23 06:39

    C語言內存泄漏問題原理

    內存泄漏問題只有在使用堆內存的時候才會出現,棧內存不存在內存泄漏問題,因為棧內存會自動分配和釋放
    發表于 03-19 11:38 ?540次閱讀
    C語言<b class='flag-5'>內存</b>泄漏問題原理

    Linux內核內存管理之內核非連續物理內存分配

    我們已經知道,最好將虛擬地址映射到連續頁幀,從而更好地利用緩存并實現更低的平均內存訪問時間。然而,如果對內存區域的請求并不頻繁,那么考慮基于通過連續線性地址訪問非連續頁幀的分配方案是有意義的。該模式
    的頭像 發表于 02-23 09:44 ?1010次閱讀
    Linux內核<b class='flag-5'>內存</b>管理之內核非連續物理<b class='flag-5'>內存</b><b class='flag-5'>分配</b>

    Linux內核內存管理之ZONE內存分配

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

    拆解mmap內存映射的本質!

    mmap 內存映射里所謂的內存其實指的是虛擬內存,在調用 mmap 進行匿名映射的時候(比如進行堆內存分配),是將進程虛擬
    的頭像 發表于 01-24 14:30 ?1804次閱讀
    拆解mmap<b class='flag-5'>內存</b>映射的本質!
    主站蜘蛛池模板: 亚洲精品色情APP在线下载观看| 四虎永久免费| cctv论坛| 中国女人逼| 野花高清在线观看免费3中文| 性色AV一区二区三区咪爱四虎| 乳色吐息未增删樱花ED在线观看| 欧美成人无码A区在线观看免费 | 久久久无码精品亚洲A片软件 | 手机看片国产日韩欧美| 日韩成人在线视频| 日韩毛片在线视频| 日韩欧美一级| 色多多污污下载| 欧美成人无码视频午夜福利| 99热久久视频只有精品6国产| 久久婷婷五月免费综合色啪| 久久精品人人做人人爽97| 日韩一区二区三区视频在线观看| 老子午夜伦不卡电影院| 久草在在线免视频在线观看| 好湿好紧水多AAAAA片秀人网| 花蝴蝶高清在线视频免费观看 | 亚洲精品不卡在线| 忘忧草在线社区WWW日本直播| 无套内射CHINESEHD熟女| 午夜在线播放免费人成无| 亚洲AV永久无码精品老司机蜜桃| 亚洲精品m在线观看| 亚洲一区精品伊人久久伊人| 在线视频久久只有精品第一日韩| 97精品免费视频| 北原夏美 快播| 国产精品视频免费视频| 久久999视频| 欧美肥婆性生活| 四虎永久在线精品免费A| 亚洲欧美一区二区久久| 最近2019年日本中文免费字幕| CHINSEFUCKGAY无套| 国产精品av免费观看|