Home Performance Optimization GPU Memory Tracking GPU Memory Tracking
Overview # In version 1.40, Prysm introduces GPU memory tracking. This comes with the ability to extract detailed information about the allocated GPU memory in the Library and the ability to reset the GPU memory peaks. That makes it easier to check the memory statistics of the allocated resources.
NOTE This API is only available in a Developer configuration.
This page provides details about the feature, a list of everything we track, a sample of how to obtain the information, as well as a few general considerations for extracting the information.
We have developed a structure to hold the GPU memory data called GPUMemoryInfo, which can be filled with all the tracked information using the help of the GetGPUMemoryStats() method found in the Library. As for user textures, which are tracked separately from the rest of the GPU memory, the cohtml::UserGPUMemoryInfo* Library::GetUserGPUMemoryStats() method can be used to retrieve their information, which is encapsulated in a different structure called UserGPUMemoryInfo. The GPUMemoryInfo::Release() method must be called on the returned cohtml::GPUMemoryInfo* or cohtml::UserGPUMemoryInfo* pointer to free its allocated memory. The statistics from the Library include all shared resources across the Views. A list of every member in the GPUMemoryInfo and UserGPUMemoryInfo structures along with a description of what each member tracks is provided below.
How to reset GPU memory peaks # In order to reset the accumulated memory peaks to match the current state, the ResetGPUMemoryTrackerPeaks() method of the Library needs to be invoked. Resetting the peaks of the Library will also reset the user textures' peaks.
A list of all the monitored GPU memory data # >
All GPU memory is tracked in bytes .
GPUMemoryInfo structure # Member Description size_t TotalBytes;The total GPU memory size_t PeakBytes;The highest GPU memory reached TextureInfo TexturesInformation[renoir::domains::TextureType::TT_Count];An array of TextureInfo objects containing all tracked textures' information separated by their TextureType. Only the color textures' (TT_ColorTexture) info is stored here TextureResources DSTexturesInformation;A TextureResources object containing all tracked Depth-Stencil textures' information BufferInfo BuffersInformation[renoir::domains::BufferType::BT_Count];An array of BufferInfo objects containing all tracked buffers' information separated by their BufferType ExtraColorImageTexturesInfo ExtraColorImageTexturesInformation;An array of additional information about the texture, like it’s name and which views it is used in. The ArraySize member is equal to TexturesInformation[renoir::domains::TextureType::TT_ColorTexture].ResourceArray[renoir::domains::TextureDomain::T_ImageTexture].ArraySize, so the index used to iterate the image color textures can be directly used to iterate the extra information.
In-depth description of TexturesInformation’s members # Member Description TexturesInformation[TT_ColorTexture]Color texture statistics. TexturesInformation[TT_DepthTexture]Deprecated field, which used to store Depth-Stencil texture statistics. Now stored in DSTexturesInformation TexturesInformation[TT_ColorTexture].Total.BytesThe total GPU memory of all color textures TexturesInformation[TT_ColorTexture].Total.CountThe count of all current color textures TexturesInformation[TT_ColorTexture].Peak.BytesThe highest reached GPU memory of all color textures TexturesInformation[TT_ColorTexture].Peak.CountThe highest reached count of all color textures TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain]Color texture statistics by TextureDomain. Array size is TextureDomain::T_Count TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Total.BytesThe total GPU memory of all color textures from the specified TextureDomain TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Total.CountThe count of all current color textures from the specified TextureDomain TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Peak.BytesThe highest reached GPU memory of all color textures from the specified TextureDomain TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Peak.CountThe highest reached count of all color textures from the specified TextureDomain TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].ArrayTexture statistics of all current color textures from the specified TextureDomain TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].ArraySizeThe Array size. Same as TexturesInformation[renoir::domains::TextureType::TT_ColorTexture].ResourceArray[TextureDomain].Total.Count TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Array[ind].IdThe color texture’s ID TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Array[ind].BytesThe color texture’s size TexturesInformation[TT_ColorTexture].ResourceArray[TextureDomain].Array[ind].OwnerIdThe color texture’s scene ID. If it instead belongs to the Library, the ID will equal unsigned(-1) aka RENOIR_INVALID
In-depth description of DSTexturesInformation’s members # Member Description DSTexturesInformationDepth-Stencil texture statistics DSTexturesInformation.Total.BytesThe total GPU memory of all Depth-Stencil textures DSTexturesInformation.Total.CountThe count of all current Depth-Stencil textures DSTexturesInformation.Peak.BytesThe highest reached GPU memory of all Depth-Stencil textures DSTexturesInformation.Peak.CountThe highest reached count of all Depth-Stencil textures DSTexturesInformation.ArrayDepth-Stencil Texture statistics of all current Depth-Stencil textures DSTexturesInformation.ArraySizeThe Array size. Same as DSTexturesInformation.Total.Count DSTexturesInformation.Array[ind].IdThe Depth-Stencil texture’s ID DSTexturesInformation.Array[ind].BytesThe Depth-Stencil texture’s size DSTexturesInformation.Array[ind].OwnerIdThe Depth-Stencil texture’s owner. All DS textures belong to the Library, so the ID equals unsigned(-1) aka RENOIR_INVALID
Member Description BuffersInformation[BufferType]Buffer statistics by BufferType. Array size is BufferType::BT_Count BuffersInformation[BufferType].Total.BytesThe total GPU memory of all buffers from the specified BufferType BuffersInformation[BufferType].Total.CountThe count of all current buffers from the specified BufferType BuffersInformation[BufferType].Peak.BytesThe highest reached GPU memory of all buffers from the specified BufferType BuffersInformation[BufferType].Peak.CountThe highest reached count of all buffers from the specified BufferType BuffersInformation[BufferType].ResourceArray[MAX_BUFFER_DOMAIN_COUNT]Buffer statistics by domain for the specified BufferType. Size is indicated by the buffer domain’s count (IB_Count, VB_Count, CB_Count) BuffersInformation[BufferType].ResourceArray[BufferDomain].Total.BytesThe total GPU memory of all buffers from the specified BufferDomain and BufferType BuffersInformation[BufferType].ResourceArray[BufferDomain].Total.CountThe count of all current buffers from the specified BufferDomain and BufferType BuffersInformation[BufferType].ResourceArray[BufferDomain].Peak.BytesThe highest reached allocated GPU memory of all buffers from the specified BufferDomain and BufferType BuffersInformation[BufferType].ResourceArray[BufferDomain].Peak.CountThe highest reached count of all buffers from the specified BufferDomain and BufferType BuffersInformation[BufferType].ResourceArray[BufferDomain].ArrayBuffer statistics of all current buffers from the specified BufferDomain and BufferType BuffersInformation[BufferType].ResourceArray[BufferDomain].ArraySizeThe Array size. Same as BuffersInformation[BufferType].ResourceArray[BufferDomain].Total.Count BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].IdThe buffer’s ID BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].BytesThe buffer’s allocated size BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].PeakUsageBytesThe highest amount of bytes used from the buffer’s allocated memory BuffersInformation[BufferType].ResourceArray[BufferDomain].Array[ind].OwnerIdThe buffer’s scene ID. If it instead belongs to the Library, the ID will equal unsigned(-1) aka RENOIR_INVALID
Member Description ExtraColorImageTexturesInformation.Array[ind].NameThe name of the texture ExtraColorImageTexturesInformation.Array[ind].ViewClientsCountThe total amount of views this texture is registered in ExtraColorImageTexturesInformation.Array[ind].ViewClientsThe array of views this texture is registered in
UserGPUMemoryInfo structure # Member Description UserTexturesInfo UserTextureInformationContains information for all tracked user textures RenderTargetInfo RenderTargetInformation[renoir::domains::TextureType::TT_Count]An array of RenderTargetInfo objects containing all tracked render targets' information separated by their TextureType ExtraUserImageInfo ExtraUserImageInformationContains additional information about an image, such as it’s name and how many views it is used in
In-depth description of the UserTexturesInfo’s members # Member Description GPUMemoryInfo::MemoryInfo TotalUsageTotal GPU memory used by user images (TotalUsage.Bytes), based on their content size, and the user images' current count (TotalUsage.Count) GPUMemoryInfo::MemoryInfo PeakUsagePeak GPU memory used by user images - highest recorded value of TotalUsage.Bytes and TotalUsage.Count GPUMemoryInfo::MemoryInfo TotalTotal GPU memory used by unique user objects (Total.Bytes) and their current count (Total.Count). Each user object is counted only once, even if reused across multiple user images GPUMemoryInfo::MemoryInfo PeakPeak GPU memory used by unique user objects - highest recorded value of Total.Bytes and Total.Count size_t ArraySizeSize of Array UserTextureInformation.Array[ind].IdThe user texture’s ID UserTextureInformation.Array[ind].OwnerIdThe user texture’s owner. All user textures belong to the Library, so the ID equals unsigned(-1) aka RENOIR_INVALID UserTextureInformation.Array[ind].BytesThe size of the user texture in bytes UserTextureInformation.Array[ind].UserObjectThe user object data itself UserTextureInformation.Array[ind].UserObjectBytesThe size of the user object data in bytes
In-depth description of the RenderTargetInfo’s members # Member Description GPUMemoryInfo::MemoryInfo TotalThe total render targets' GPU memory (Total.Bytes) and their current count (Total.Count) GPUMemoryInfo::MemoryInfo PeakThe highest reached render targets' GPU memory (Peak.Bytes) and the highest reached peaks count (Peak.Count) size_t ArraySize;Size of Array RenderTargetInformation.Array[ind].IdThe render target’s ID RenderTargetInformation.Array[ind].OwnerIdThe render target’s owner RenderTargetInformation.Array[ind].BytesThe size of the render target in bytes RenderTargetInformation.Array[ind].UserObjectThe actual data RenderTargetInformation.Array[ind].WidthThe width of the render target RenderTargetInformation.Array[ind].HeightThe height of the render target RenderTargetInformation.Array[ind].SamplesCountThe sample count
Member Description size_t ArraySize;Size of Array ExtraUserImageInformation.Array[ind].NameThe name of the user image ExtraUserImageInformation.Array[ind].ViewClientsCountThe total amount of views this user image is registered in ExtraUserImageInformation.Array[ind].ViewClientsThe array of views this user image is registered in
Resource domains # namespace domains
{
enum TextureType
{
TT_ColorTexture = 0,
TT_DepthTexture,
TT_Count
};
enum BufferType
{
BT_IndexBuffer = 0,
BT_VertexBuffer,
BT_ConstantBuffer,
BT_Count
};
enum TextureDomain
{
T_ScratchTexture = 0,
T_LayerTexture,
T_ImageTexture,
T_SurfaceTexture,
T_CompositorTexture,
T_GlyphAtlas,
T_GradientCacheTexture,
T_Count
};
enum VBDomain // Vertex Buffer Domain
{
VB_GeometryBuffer = 0,
VB_PathBuffer,
VB_GlyphBuffer,
VB_Count
};
enum IBDomain // Index Buffer Domain
{
IB_GeometryBuffer = 0,
IB_PathBuffer,
IB_GlyphBuffer,
IB_Count
};
enum CBDomain // Constant Buffer Domain (same as CBType)
{
// Vertex shader CBs
CB_DataVS,
// Pixel shader CBs
CB_DataPS,
CB_Count
};
}
Below are example functions that show how to display GPU memory information.
void PrintToLog(const cohtml::GPUMemoryInfo* memoryStats)
{
std::ostringstream oss;
oss << "---------- Total GPU Memory Stats ----------" << std::endl;
oss << "\tTotal GPU Memory: " << memoryStats->TotalBytes << " bytes" << std::endl;
oss << "\tPeak GPU Memory: " << memoryStats->PeakBytes << " bytes" << std::endl;
oss << "\t> Main textures memory info:" << std::endl;
oss << "\tTotal color textures memory: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Total.Bytes << " bytes" << std::endl;
oss << "\tTotal depth textures memory: " << memoryStats->DSTexturesInformation.Total.Bytes << " bytes" << std::endl;
oss << "\tPeak color textures memory: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Peak.Bytes << " bytes" << std::endl;
oss << "\tPeak depth textures memory: " << memoryStats->DSTexturesInformation.Peak.Bytes << " bytes" << std::endl;
oss << "\t> Main buffers memory info:" << std::endl;
oss << "\tTotal Index Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Total.Bytes << " bytes" << std::endl;
oss << "\tTotal Vertex Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Total.Bytes << " bytes" << std::endl;
oss << "\tTotal Constant Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Total.Bytes << " bytes" << std::endl;
oss << "\tPeak Index Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Peak.Bytes << " bytes" << std::endl;
oss << "\tPeak Vertex Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Peak.Bytes << " bytes" << std::endl;
oss << "\tPeak Constant Buffers memory: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Peak.Bytes << " bytes" << std::endl;
oss << "\t> Textures count info:" << std::endl;
oss << "\tTotal count of color textures: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Total.Count << std::endl;
oss << "\tTotal count of depth textures: " << memoryStats->DSTexturesInformation.Total.Count << std::endl;
oss << "\tPeak count of color textures: " << memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].Peak.Count << std::endl;
oss << "\tPeak count of depth textures: " << memoryStats->DSTexturesInformation.Peak.Count << std::endl;
oss << "\t> Buffers count info:" << std::endl;
oss << "\tTotal count of Index Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Total.Count << std::endl;
oss << "\tTotal count of Vertex Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Total.Count << std::endl;
oss << "\tTotal count of Constant Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Total.Count << std::endl;
oss << "\tPeak count of Index Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_IndexBuffer].Peak.Count << std::endl;
oss << "\tPeak count of Vertex Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_VertexBuffer].Peak.Count << std::endl;
oss << "\tPeak count of Constant Buffers: " << memoryStats->BuffersInformation[renoir::domains::BT_ConstantBuffer].Peak.Count << std::endl;
const char* textureStrings[] = { "Scratch Texture", "Layer Texture", "Image Texture", "Surface Texture", "Compositor Texture", "Glyph Atlase", "Gradient Cache Texture" };
const char* bufferStrings[] = { "Index Geometry Buffer", "Index Path Buffer", "Index Glyph Buffer",
"Vertex Geometry Buffer", "Vertex Path Buffer", "Vertex Path Instance Data Buffer", "Vertex Glyph Buffer",
"VS Data Constant Buffer", "PS Data Constant Buffer" };
APP_LOG(Info, oss.str().c_str());
oss.str("");
for (size_t texDomain = 0; texDomain < renoir::domains::TextureDomain::T_Count; ++texDomain)
{
oss << "\t> Color " << textureStrings[texDomain] << "s:" << std::endl;
auto& domainInfo = memoryStats->TexturesInformation[renoir::domains::TT_ColorTexture].ResourceArray[texDomain];
oss << "\tTotal memory: " << domainInfo.Total.Bytes << " bytes" << std::endl;
oss << "\tTotal count: " << domainInfo.Total.Count << std::endl;
oss << "\tPeak memory: " << domainInfo.Peak.Bytes << " bytes" << std::endl;
oss << "\tPeak count: " << domainInfo.Peak.Count << std::endl;
for (size_t i = 0; i < domainInfo.ArraySize; i++)
{
oss << "\tID: " << domainInfo.Array[i].Id << "; Owner: ";
if (domainInfo.Array[i].OwnerId == RENOIR_INVALID)
{
oss << "Shared";
}
else
{
oss << domainInfo.Array[i].OwnerId;
}
oss << "; Size: " << domainInfo.Array[i].Bytes << " bytes";
if (texDomain == renoir::domains::TextureDomain::T_ImageTexture &&
memoryStats->ExtraColorImageTexturesInformation.Array[i].Name)
{
oss << "; View client IDs:";
for (size_t viewCount = 0; viewCount < memoryStats->ExtraColorImageTexturesInformation.Array[i].ViewClientsCount; ++viewCount)
{
oss << " " << memoryStats->ExtraColorImageTexturesInformation.Array[i].ViewClients[viewCount];
}
oss << std::endl << "\t\tTexture Name: " << memoryStats->ExtraColorImageTexturesInformation.Array[i].Name << std::endl;
}
else
{
oss << std::endl;
}
}
APP_LOG(Info, oss.str().c_str());
oss.str("");
}
oss << "\t> Depth Stencil Textures: " << std::endl;
oss << "\tTotal memory: " << memoryStats->DSTexturesInformation.Total.Bytes << " bytes" << std::endl;
oss << "\tTotal count: " << memoryStats->DSTexturesInformation.Total.Count << std::endl;
oss << "\tPeak memory: " << memoryStats->DSTexturesInformation.Peak.Bytes << " bytes" << std::endl;
oss << "\tPeak count: " << memoryStats->DSTexturesInformation.Peak.Count << std::endl;
for (size_t i = 0; i < memoryStats->DSTexturesInformation.ArraySize; i++)
{
oss << "\tID: " << memoryStats->DSTexturesInformation.Array[i].Id << "; Owner: ";
if (memoryStats->DSTexturesInformation.Array[i].OwnerId == RENOIR_INVALID)
{
oss << "Shared";
}
else
{
oss << memoryStats->DSTexturesInformation.Array[i].OwnerId;
}
oss << "; Size: " << memoryStats->DSTexturesInformation.Array[i].Bytes << " bytes" << std::endl;
}
APP_LOG(Info, oss.str().c_str());
oss.str("");
for (size_t buffType = 0; buffType < renoir::domains::BufferType::BT_Count; ++buffType)
{
size_t buffDomainSize = buffType == renoir::domains::BufferType::BT_IndexBuffer ? renoir::domains::IB_Count :
buffType == renoir::domains::BufferType::BT_VertexBuffer ? renoir::domains::VB_Count : renoir::CB_Count;
size_t buffStringsStart = buffType == renoir::domains::BufferType::BT_IndexBuffer ? 0 :
buffType == renoir::domains::BufferType::BT_VertexBuffer ? renoir::domains::IB_Count : renoir::domains::IB_Count + renoir::domains::VB_Count;
for (size_t buffDomain = 0; buffDomain < buffDomainSize; buffDomain++)
{
oss << "\t> " << bufferStrings[buffStringsStart + buffDomain] << "s:" << std::endl;
auto& domainInfo = memoryStats->BuffersInformation[buffType].ResourceArray[buffDomain];
oss << "\tTotal memory: " << domainInfo.Total.Bytes << " bytes" << std::endl;
oss << "\tTotal count: " << domainInfo.Total.Count << std::endl;
oss << "\tPeak memory: " << domainInfo.Peak.Bytes << " bytes" << std::endl;
oss << "\tPeak count: " << domainInfo.Peak.Count << std::endl;
for (size_t i = 0; i < domainInfo.ArraySize; i++)
{
oss << "\tID: " << domainInfo.Array[i].Id << "; Owner: ";
if (domainInfo.Array[i].OwnerId == RENOIR_INVALID)
{
oss << "Shared";
}
else
{
oss << domainInfo.Array[i].OwnerId;
}
oss << "; Size: " << domainInfo.Array[i].Bytes << " bytes";
oss << "; Peak usage: " << domainInfo.Array[i].PeakUsageBytes << " bytes" << std::endl;
}
APP_LOG(Info, oss.str().c_str());
oss.str("");
}
}
}
void PrintToLog(const cohtml::UserGPUMemoryInfo* memoryStats)
{
TmpOSStream oss;
oss << "\t---------- User GPU Memory Stats ----------" << std::endl;
oss << "\tTotal GPU Memory: " << memoryStats->Total.Bytes << " bytes" << std::endl;
oss << "\tPeak GPU Memory: " << memoryStats->Peak.Bytes << " bytes" << std::endl;
oss << "\tTotal texture count: " << memoryStats->Total.Count << std::endl;
oss << "\tPeak texture count: " << memoryStats->Peak.Count << std::endl;
if (memoryStats->ArraySize > 0)
{
oss << "\t---------- Textures ----------" << std::endl;
}
for (size_t i = 0; i < memoryStats->ArraySize; i++)
{
const auto& texture = memoryStats->Array[i];
oss << "\tID: " << texture.Id << ";\tSize: " << texture.Bytes << " bytes" << std::endl;
oss << "\tName: " << texture.Name << std::endl;
oss << "\tView Clients Count: " << texture.ViewClientsCount << std::endl;
for (size_t viewCount = 0; viewCount < texture.ViewClientsCount; ++viewCount)
{
oss << "\tView Client Id: " << texture.ViewClients[viewCount] << std::endl;
}
}
APP_LOG(Info, oss.str().c_str());
}
We have already implemented them and they can be used like this
void PrintGPUMemoryStats()
{
auto combinedMemoryStats = m_CohtmlApp->GetLibrary()->GetGPUMemoryStats();
if (combinedMemoryStats)
{
combinedMemoryStats->PrintToLog();
combinedMemoryStats->Release();
}
}
void PrintUserGPUMemoryStats()
{
auto userMemoryStats = m_CohtmlApp->GetLibrary()->GetUserGPUMemoryStats();
if (userMemoryStats)
{
userMemoryStats->PrintToLog();
userMemoryStats->Release();
}
}