Skip to content

Commit 5eb392b

Browse files
committed
Continued initial work on memory pressure handling
1 parent fd8f6f6 commit 5eb392b

File tree

3 files changed

+88
-43
lines changed

3 files changed

+88
-43
lines changed

scopehal/AcceleratorBuffer.h

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,38 @@ extern bool g_vulkanDeviceHasUnifiedMemory;
6262
template<class T>
6363
class AcceleratorBuffer;
6464

65+
///@brief Levels of memory pressure
66+
enum class MemoryPressureLevel
67+
{
68+
///@brief A memory allocation has failed and we need to free memory immediately to continue execution
69+
Hard,
70+
71+
/**
72+
@brief Free memory has reached a warning threshold.
73+
74+
We should trim caches or otherwise try to make space but don't need to be too aggressive about it.
75+
76+
This level is only available if we have VK_EXT_memory_budget; without this extension we do not know about
77+
memory pressure until a hard allocation failure occurs.
78+
*/
79+
Soft
80+
};
81+
82+
///@brief Types of memory pressure
83+
enum class MemoryPressureType
84+
{
85+
///@brief Pinned CPU-side memory
86+
Host,
87+
88+
///@brief GPU-side memory
89+
Device
90+
};
91+
92+
///@brief Memory pressure handler type, called when free memory reaches a warning level or a Vulkan allocation fails
93+
typedef bool (*MemoryPressureHandler)(MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize);
94+
95+
bool OnMemoryPressure(MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize);
96+
6597
template<class T>
6698
class AcceleratorBufferIterator
6799
{
@@ -1263,9 +1295,43 @@ class AcceleratorBuffer
12631295
//(may be rounded up from what we asked for)
12641296
auto req = m_gpuBuffer->getMemoryRequirements();
12651297

1266-
//For now, always use local memory
1298+
//Try to allocate the memory
12671299
vk::MemoryAllocateInfo info(req.size, g_vkLocalMemoryType);
1268-
m_gpuPhysMem = std::make_unique<vk::raii::DeviceMemory>(*g_vkComputeDevice, info);
1300+
try
1301+
{
1302+
//For now, always use local memory
1303+
m_gpuPhysMem = std::make_unique<vk::raii::DeviceMemory>(*g_vkComputeDevice, info);
1304+
}
1305+
1306+
//Fallback path in case of low memory
1307+
catch(vk::OutOfDeviceMemoryError& ex)
1308+
{
1309+
bool ok = false;
1310+
while(!ok)
1311+
{
1312+
//Attempt to free memory and stop if we couldn't free more
1313+
if(!OnMemoryPressure(MemoryPressureLevel::Hard, MemoryPressureType::Device, req.size))
1314+
break;
1315+
1316+
///Retry the allocation
1317+
try
1318+
{
1319+
m_gpuPhysMem = std::make_unique<vk::raii::DeviceMemory>(*g_vkComputeDevice, info);
1320+
ok = true;
1321+
}
1322+
catch(vk::OutOfDeviceMemoryError& ex2)
1323+
{
1324+
LogDebug("Allocation failed again\n");
1325+
}
1326+
}
1327+
1328+
//If we get here, we couldn't allocate no matter what
1329+
LogError(
1330+
"Failed to allocate %s of GPU memory despite our best efforts to reclaim space\n"
1331+
"This is unrecoverable (for now).\n",
1332+
Unit(Unit::UNIT_BYTES).PrettyPrint(req.size).c_str());
1333+
exit(1);
1334+
}
12691335
m_gpuMemoryType = MEM_TYPE_GPU_ONLY;
12701336

12711337
m_gpuBuffer->bindMemory(**m_gpuPhysMem, 0);
@@ -1348,4 +1414,6 @@ class AcceleratorBuffer
13481414

13491415
};
13501416

1417+
extern std::set<MemoryPressureHandler> g_memoryPressureHandlers;
1418+
13511419
#endif

scopehal/scopehal.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -994,16 +994,27 @@ const char* ScopehalGetVersion()
994994
/**
995995
@brief Called when we run low on memory
996996
997-
@param level Indicates if this is a soft or hard memory exhaustion condition
998-
@param type Indicates if we are low on CPU or GPU memory
997+
@param level Indicates if this is a soft or hard memory exhaustion condition
998+
@param type Indicates if we are low on CPU or GPU memory
999+
@param requestedSize For hard memory exhaustion, the size of the failing allocation.
1000+
For soft exhaustion, ignored and set to zero
1001+
1002+
@return True if memory was freed, false if no space could be freed
9991003
*/
1000-
void OnMemoryPressure(MemoryPressureLevel level, MemoryPressureType type)
1004+
bool OnMemoryPressure(MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize)
10011005
{
1002-
LogWarning("OnMemoryPressure: %s memory exhaustion on %s\n",
1006+
LogWarning("OnMemoryPressure: %s memory exhaustion on %s (tried to allocate %s)\n",
10031007
(level == MemoryPressureLevel::Hard) ? "Hard" : "Soft",
1004-
(type == MemoryPressureType::Host) ? "host" : "device");
1005-
LogIndenter li;
1008+
(type == MemoryPressureType::Host) ? "host" : "device",
1009+
Unit(Unit::UNIT_BYTES).PrettyPrint(requestedSize).c_str());
1010+
1011+
bool moreFreed = false;
10061012

10071013
for(auto handler : g_memoryPressureHandlers)
1008-
handler(level, type);
1014+
{
1015+
if(handler(level, type, requestedSize))
1016+
moreFreed = true;
1017+
}
1018+
1019+
return moreFreed;
10091020
}

scopehal/scopehal.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -272,38 +272,4 @@ uint32_t ColorFromString(const std::string& str, unsigned int alpha = 255);
272272

273273
const char* ScopehalGetVersion();
274274

275-
///@brief Levels of memory pressure
276-
enum class MemoryPressureLevel
277-
{
278-
///@brief A memory allocation has failed and we need to free memory immediately to continue execution
279-
Hard,
280-
281-
/**
282-
@brief Free memory has reached a warning threshold.
283-
284-
We should trim caches or otherwise try to make space but don't need to be too aggressive about it.
285-
286-
This level is only available if we have VK_EXT_memory_budget; without this extension we do not know about
287-
memory pressure until a hard allocation failure occurs.
288-
*/
289-
Soft
290-
};
291-
292-
///@brief Types of memory pressure
293-
enum class MemoryPressureType
294-
{
295-
///@brief Pinned CPU-side memory
296-
Host,
297-
298-
///@brief GPU-side memory
299-
Device
300-
};
301-
302-
///@brief Memory pressure handler type, called when free memory reaches a warning level or a Vulkan allocation fails
303-
typedef void (*MemoryPressureHandler)(MemoryPressureLevel level, MemoryPressureType type);
304-
305-
extern std::set<MemoryPressureHandler> g_memoryPressureHandlers;
306-
307-
void OnMemoryPressure(MemoryPressureLevel level, MemoryPressureType type);
308-
309275
#endif

0 commit comments

Comments
 (0)