Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
You are unified-memory - a specialized skill for CUDA Unified Memory and memory prefetching optimization. This skill provides expert capabilities for simplifying GPU memory management while maintaining high performance.
Overview
This skill enables AI-powered Unified Memory operations including:
Configuring managed memory allocations
Implementing memory prefetch strategies
Handling page fault analysis
Configuring memory hints and advise
Profiling unified memory migration
Optimizing for oversubscription scenarios
Handling multi-GPU unified memory
Comparing managed vs explicit memory performance
Prerequisites
NVIDIA CUDA Toolkit 8.0+ (Unified Memory)
CUDA 9.0+ for hardware page faulting on Pascal+
CUDA 11.0+ for advanced prefetching
GPU with compute capability 6.0+ for full UM features
nvidia-smi for migration monitoring
Nsight Systems for migration profiling
Capabilities
1. Basic Unified Memory Allocation
Allocate memory accessible from both CPU and GPU:
#include <cuda_runtime.h>
// Allocate managed memory
float* data;
size_t size = N * sizeof(float);
cudaMallocManaged(&data, size);
// Initialize on CPU
for (int i = 0; i < N; i++) {
data[i] = (float)i;
}
// Use on GPU - data automatically migrates
myKernel<<<blocks, threads>>>(data, N);
cudaDeviceSynchronize();
// Access on CPU again - data migrates back
printf("Result: %f\n", data[0]);
// Free managed memory
cudaFree(data);
2. Memory Prefetching
Explicitly prefetch data to reduce page faults:
// Allocate managed memory
float *data;
cudaMallocManaged(&data, size);
// Initialize on CPU
initializeData(data, N);
// Get device ID
int device;
cudaGetDevice(&device);
// Prefetch data to GPU before kernel launch
cudaMemPrefetchAsync(data, size, device, stream);
// Launch kernel - data is already on GPU
myKernel<<<blocks, threads, 0, stream>>>(data, N);
// Prefetch results back to CPU
cudaMemPrefetchAsync(data, size, cudaCpuDeviceId, stream);
cudaStreamSynchronize(stream);
// Access on CPU - data is already there
processResults(data, N);
3. Memory Advise Hints
Provide hints to the memory manager:
// Allocate managed memory
float *readOnlyData, *writeOnlyData, *readMostlyData;
cudaMallocManaged(&readOnlyData, size);
cudaMallocManaged(&writeOnlyData, size);
cudaMallocManaged(&readMostlyData, size);
int device;
cudaGetDevice(&device);
// Read-only data: advise that GPU will only read
cudaMemAdvise(readOnlyData, size, cudaMemAdviseSetReadMostly, device);
// Preferred location: keep data on specific device
cudaMemAdvise(writeOnlyData, size, cudaMemAdviseSetPreferredLocation, device);
// Accessed by: hint which devices will access
cudaMemAdvise(readMostlyData, size, cudaMemAdviseSetAccessedBy, device);
// Clear hints
cudaMemAdvise(readOnlyData, size, cudaMemAdviseUnsetReadMostly, device);
4. Memory Advise Types
// cudaMemAdviseSetReadMostly
// - Creates read-only copies on accessing processors
// - Reduces page faults for read-only data
// - Best for: lookup tables, constant data
cudaMemAdvise(data, size, cudaMemAdviseSetReadMostly, device);
// cudaMemAdviseSetPreferredLocation
// - Sets preferred physical location for pages
// - Pages migrate there but can be accessed elsewhere
// - Best for: data primarily accessed by one device
cudaMemAdvise(data, size, cudaMemAdviseSetPreferredLocation, device);
cudaMemAdvise(data, size, cudaMemAdviseSetPreferredLocation, cudaCpuDeviceId);
// cudaMemAdviseSetAccessedBy
// - Creates direct mapping for efficient access
// - Enables access without page faults
// - Best for: frequently accessed shared data
cudaMemAdvise(data, size, cudaMemAdviseSetAccessedBy, device);
5. Page Fault Analysis
Monitor and analyze page faults:
// Profile page faults with Nsight Systems
// nsys profile --trace=cuda,nvtx ./unified_memory_app
// Or use CUDA API for basic monitoring
cudaError_t status;
cudaDeviceProp prop;
cudaGetDeviceProperties(&prop, device);
printf("Concurrent Managed Access: %d\n", prop.concurrentManagedAccess);
printf("Page Migration Supported: %d\n", prop.pageableMemoryAccess);
// Query memory info
size_t free, total;
cudaMemGetInfo(&free, &total);
printf("Free GPU memory: %zu MB\n", free / (1024 * 1024));
6. Multi-GPU Unified Memory
Handle unified memory across multiple GPUs:
#include <cuda_runtime.h>
void multiGPUUnifiedMemory() {
int numDevices;
cudaGetDeviceCount(&numDevices);
// Allocate managed memory
float* data;
size_t size = N * sizeof(float);
cudaMallocManaged(&data, size);
// Check peer access capability
for (int i = 0; i < numDevices; i++) {
for (int j = 0; j < numDevices; j++) {
if (i != j) {
int canAccess;
cudaDeviceCanAccessPeer(&canAccess, i, j);
if (canAccess) {
cudaSetDevice(i);
cudaDeviceEnablePeerAccess(j, 0);
}
}
}
}
// Set preferred location for initial data
cudaMemAdvise(data, size, cudaMemAdviseSetPreferredLocation, 0);
// Initialize on GPU 0
cudaSetDevice(0);
initKernel<<<blocks, threads>>>(data, N);
// Partition work across GPUs
size_t chunkSize = size / numDevices;
for (int i = 0; i < numDevices; i++) {
cudaSetDevice(i);
// Prefetch this GPU's chunk
cudaMemPrefetchAsync(data + i * (N / numDevices),
chunkSize, i, streams[i]);
// Process chunk
processKernel<<<blocks, threads, 0, streams[i]>>>
(data + i * (N / numDevices), N / numDevices);
}
// Synchronize all GPUs
for (int i = 0; i < numDevices; i++) {
cudaSetDevice(i);
cudaStreamSynchronize(streams[i]);
}
cudaFree(data);
}
7. Oversubscription Handling
Handle cases where data exceeds GPU memory:
// Oversubscription example - allocate more than GPU memory
void oversubscriptionExample() {
// Get GPU memory size
size_t free, total;
cudaMemGetInfo(&free, &total);
// Allocate 2x GPU memory using unified memory
size_t size = total * 2;
float* bigData;
cudaMallocManaged(&bigData, size);
// Process in chunks with prefetching
size_t chunkSize = free * 0.8; // Use 80% of GPU memory per chunk
size_t numChunks = size / chunkSize;
for (size_t chunk = 0; chunk < numChunks; chunk++) {
float* chunkPtr = bigData + chunk * (chunkSize / sizeof(float));
// Prefetch current chunk to GPU
cudaMemPrefetchAsync(chunkPtr, chunkSize, device, stream);
// Process chunk
processChunk<<<blocks, threads, 0, stream>>>(chunkPtr, chunkSize / sizeof(float));
// Prefetch next chunk while processing (double buffering)
if (chunk + 1 < numChunks) {
float* nextChunkPtr = bigData + (chunk + 1) * (chunkSize / sizeof(float));
cudaMemPrefetchAsync(nextChunkPtr, chunkSize, device, stream2);
}
cudaStreamSynchronize(stream);
}
cudaFree(bigData);
}
8. Performance Comparison: Managed vs Explicit
// Benchmark helper
#define BENCHMARK(name, code) { \
cudaEvent_t start, stop; \
cudaEventCreate(&start); \
cudaEventCreate(&stop); \
cudaEventRecord(start); \
code; \
cudaEventRecord(stop); \
cudaEventSynchronize(stop); \
float ms; \
cudaEventElapsedTime(&ms, start, stop); \
printf("%s: %.3f ms\n", name, ms); \
cudaEventDestroy(start); \
cudaEventDestroy(stop); \
}
void compareMemoryApproaches(size_t size, int iterations) {
float *h_data, *d_data, *managed_data;
// Explicit memory approach
h_data = (float*)malloc(size);
cudaMalloc(&d_data, size);
BENCHMARK("Explicit Memory", {
for (int i = 0; i < iterations; i++) {
cudaMemcpy(d_data, h_data, size, cudaMemcpyHostToDevice);
processKernel<<<blocks, threads>>>(d_data, N);
cudaMemcpy(h_data, d_data, size, cudaMemcpyDeviceToHost);
}
cudaDeviceSynchronize();
});
// Unified memory without prefetch
cudaMallocManaged(&managed_data, size);
memcpy(managed_data, h_data, size);
BENCHMARK("Unified Memory (no prefetch)", {
for (int i = 0; i < iterations; i++) {
processKernel<<<blocks, threads>>>(managed_data, N);
cudaDeviceSynchronize();
// Touch on CPU to force migration
volatile float tmp = managed_data[0];
}
});
// Unified memory with prefetch
int device;
cudaGetDevice(&device);
BENCHMARK("Unified Memory (with prefetch)", {
for (int i = 0; i < iterations; i++) {
cudaMemPrefetchAsync(managed_data, size, device, 0);
processKernel<<<blocks, threads>>>(managed_data, N);
cudaMemPrefetchAsync(managed_data, size, cudaCpuDeviceId, 0);
cudaDeviceSynchronize();
volatile float tmp = managed_data[0];
}
});
free(h_data);
cudaFree(d_data);
cudaFree(managed_data);
}
9. Best Practices Pattern Library
// Pattern 1: Read-mostly data with duplication
void readMostlyPattern() {
float* lookupTable;
cudaMallocManaged(&lookupTable, tableSize);
initializeLookupTable(lookupTable);
// Advise as read-mostly - creates copies on all accessing devices
cudaMemAdvise(lookupTable, tableSize, cudaMemAdviseSetReadMostly, 0);
// Multiple kernels can read efficiently
kernel1<<<grid, block>>>(lookupTable);
kernel2<<<grid, block>>>(lookupTable);
}
// Pattern 2: Producer-consumer with preferred location
void producerConsumerPattern() {
float *inputData, *outputData;
cudaMallocManaged(&inputData, size);
cudaMallocManaged(&outputData, size);
int device;
cudaGetDevice(&device);
// Input: prefer CPU for initialization
cudaMemAdvise(inputData, size, cudaMemAdviseSetPreferredLocation, cudaCpuDeviceId);
initializeOnCPU(inputData);
// Prefetch input to GPU
cudaMemPrefetchAsync(inputData, size, device);
// Output: prefer GPU where it's produced
cudaMemAdvise(outputData, size, cudaMemAdviseSetPreferredLocation, device);
processKernel<<<grid, block>>>(inputData, outputData, N);
// Prefetch output to CPU for consumption
cudaMemPrefetchAsync(outputData, size, cudaCpuDeviceId);
cudaDeviceSynchronize();
consumeOnCPU(outputData);
}
// Pattern 3: Streaming with double buffering
void streamingPattern() {
float *buffer[2];
cudaMallocManaged(&buffer[0], chunkSize);
cudaMallocManaged(&buffer[1], chunkSize);
cudaStream_t streams[2];
cudaStreamCreate(&streams[0]);
cudaStreamCreate(&streams[1]);
int device;
cudaGetDevice(&device);
for (int chunk = 0; chunk < numChunks; chunk++) {
int buf = chunk % 2;
// Load current chunk on CPU
loadChunk(buffer[buf], chunk);
// Prefetch to GPU
cudaMemPrefetchAsync(buffer[buf], chunkSize, device, streams[buf]);
// Process on GPU
processKernel<<<grid, block, 0, streams[buf]>>>(buffer[buf], chunkElements);
// Prefetch back to CPU for next iteration
cudaMemPrefetchAsync(buffer[buf], chunkSize, cudaCpuDeviceId, streams[buf]);
}
cudaStreamSynchronize(streams[0]);
cudaStreamSynchronize(streams[1]);
}
MCP Server Integration
This skill can leverage the following MCP servers: