35#ifndef AcceleratorBuffer_h
36#define AcceleratorBuffer_h
90 static void LogHostDeviceCopyBlocking()
93 static void LogHostDeviceCopyNonBlocking()
96 static void LogHostDeviceCopySkipped()
101 static void LogDeviceHostCopyBlocking()
104 static void LogDeviceHostCopyNonBlocking()
107 static void LogDeviceHostCopySkipped()
112 static void LogDeviceDeviceCopyBlocking()
115 static void LogDeviceDeviceCopyNonBlocking()
118 static void LogDeviceDeviceCopySkipped()
160 static std::atomic<int64_t> m_resizeRequests;
163 static std::atomic<int64_t> m_gpuAllocations;
206 using value_type = T;
207 using iterator_category = std::forward_iterator_tag;
208 using difference_type = std::ptrdiff_t;
210 using reference = T&;
218 {
return m_buf[m_index]; }
220 size_t GetIndex()
const
227 return (m_index != it.m_index);
243{
return a.GetIndex() - b.GetIndex(); }
349 auto& etype =
typeid(T);
352 if(etype ==
typeid(int64_t))
354 else if(etype ==
typeid(uint64_t))
356 else if(etype ==
typeid(int32_t))
358 else if(etype ==
typeid(uint32_t))
360 else if(etype ==
typeid(int16_t))
362 else if(etype ==
typeid(uint16_t))
364 else if(etype ==
typeid(int8_t))
366 else if(etype ==
typeid(uint8_t))
374 auto pname = etype.name();
375 auto tmp = abi::__cxa_demangle(pname,
nullptr,
nullptr, &status);
377 std::string ret = std::string(tmp);
381 return std::string(etype.name());
387 {
return sizeof(T); }
407 MEM_ATTRIB_CPU_SIDE = 0x1,
408 MEM_ATTRIB_GPU_SIDE = 0x2,
411 MEM_ATTRIB_CPU_REACHABLE = 0x4,
412 MEM_ATTRIB_GPU_REACHABLE = 0x8,
415 MEM_ATTRIB_CPU_FAST = 0x10,
416 MEM_ATTRIB_GPU_FAST = 0x20
429 MEM_ATTRIB_CPU_SIDE | MEM_ATTRIB_CPU_REACHABLE,
433 MEM_ATTRIB_CPU_SIDE | MEM_ATTRIB_CPU_REACHABLE | MEM_ATTRIB_CPU_FAST,
438 MEM_TYPE_CPU_DMA_CAPABLE =
439 MEM_ATTRIB_CPU_SIDE | MEM_ATTRIB_CPU_REACHABLE | MEM_ATTRIB_CPU_FAST | MEM_ATTRIB_GPU_REACHABLE,
443 MEM_ATTRIB_GPU_SIDE | MEM_ATTRIB_GPU_REACHABLE | MEM_ATTRIB_GPU_FAST,
448 MEM_TYPE_GPU_DMA_CAPABLE =
449 MEM_ATTRIB_GPU_SIDE | MEM_ATTRIB_GPU_REACHABLE | MEM_ATTRIB_GPU_FAST | MEM_ATTRIB_CPU_REACHABLE
458 {
return (mt & MEM_ATTRIB_CPU_REACHABLE) != 0; }
464 {
return (mt & MEM_ATTRIB_GPU_REACHABLE) != 0; }
470 {
return (mt & MEM_ATTRIB_CPU_FAST) != 0; }
476 {
return (mt & MEM_ATTRIB_GPU_FAST) != 0; }
562 vk::EventCreateInfo eventCreateInfo;
566 ClearTransferFlags();
667 return vk::DescriptorBufferInfo(
728 void CopyFrom(
const std::vector<T>& rhs)
730 assert(std::is_trivially_copyable<T>::value);
732 PrepareForCpuAccess();
739 MarkModifiedFromCpu();
759 if(!std::is_trivially_copyable<T>::value)
761 for(
size_t i=0; i<
m_size; i++)
780 AcceleratorBufferPerformanceCounters::LogDeviceDeviceCopyBlocking();
784 vk::BufferCopy region(0, 0,
m_size *
sizeof(T));
792 AcceleratorBufferPerformanceCounters::LogDeviceDeviceCopySkipped();
802 void CopyFromNonblocking(
803 vk::raii::CommandBuffer& cmdBuf,
805 bool reallocateToMatch =
true)
816 if(!std::is_trivially_copyable<T>::value)
818 for(
size_t i=0; i<
m_size; i++)
835 AcceleratorBufferPerformanceCounters::LogDeviceDeviceCopyNonBlocking();
838 cmdBuf.pipelineBarrier(
839 vk::PipelineStageFlagBits::eComputeShader,
840 vk::PipelineStageFlagBits::eTransfer,
843 vk::AccessFlagBits::eShaderWrite,
844 vk::AccessFlagBits::eTransferRead),
849 vk::BufferCopy region(0, 0,
m_size *
sizeof(T));
853 AcceleratorBufferPerformanceCounters::LogDeviceDeviceCopySkipped();
857 ClearTransferFlags();
866 void Reallocate(
size_t size)
872 ClearTransferFlags();
893 PrepareForGpuAccess();
910 AllocateCpuBuffer(
size);
917 if(!std::is_trivially_copyable<T>::value)
919 for(
size_t i=0; i<
m_size; i++)
928 #pragma GCC diagnostic push
929 #pragma GCC diagnostic ignored "-Wclass-memaccess"
934 #pragma GCC diagnostic pop
942 FreeCpuPointer(pOld, pOldPin, type,
m_capacity);
948 AllocateCpuBuffer(
size);
977 if(AllocateGpuBuffer(
size))
981 AcceleratorBufferPerformanceCounters::LogDeviceDeviceCopyBlocking();
986 vk::BufferCopy region(0, 0,
m_size *
sizeof(T));
1007 SetCpuAccessHint(HINT_LIKELY);
1008 SetGpuAccessHint(HINT_LIKELY);
1009 AllocateCpuBuffer(
size);
1021 if(AllocateGpuBuffer(
size))
1034 SetCpuAccessHint(HINT_LIKELY);
1035 SetGpuAccessHint(HINT_LIKELY);
1036 AllocateCpuBuffer(
size);
1069 #pragma GCC diagnostic push
1070 #pragma GCC diagnostic ignored "-Warray-bounds"
1073 const T& operator[](
size_t i)
const
1077 T& operator[](
size_t i)
1080 #pragma GCC diagnostic pop
1085 void push_back(
const T& value)
1091 MarkModifiedFromCpu();
1097 void push_back_nomarkmod(
const T& value)
1118 void push_front(
const T& value)
1123 PrepareForCpuAccess();
1126 if(!std::is_trivially_copyable<T>::value)
1128 for(
size_t i=0; i<cursize; i++)
1143 MarkModifiedFromCpu();
1162 PrepareForCpuAccess();
1165 if(!std::is_trivially_copyable<T>::value)
1167 for(
size_t i=0; i<
m_size-1; i++)
1181 MarkModifiedFromCpu();
1218 if(!std::is_trivially_copyable<T>::value)
1235 void MarkModifiedFromCpu()
1240 ClearTransferFlags();
1251 void MarkModifiedFromGpu()
1256 ClearTransferFlags();
1270 void PrepareForCpuAccess()
1283 AcceleratorBufferPerformanceCounters::LogDeviceHostCopySkipped();
1346 void PrepareForCpuAccessNonblocking(vk::raii::CommandBuffer& cmdBuf,
bool skipBarrier =
false)
1359 AcceleratorBufferPerformanceCounters::LogDeviceHostCopySkipped();
1370 void PrepareForGpuAccess(
bool outputOnly =
false)
1378 SetGpuAccessHint(HINT_UNLIKELY,
true);
1391 AcceleratorBufferPerformanceCounters::LogHostDeviceCopySkipped();
1402 void PrepareForGpuAccessNonblocking(
bool outputOnly, vk::raii::CommandBuffer& cmdBuf)
1410 SetGpuAccessHint(HINT_UNLIKELY,
true);
1423 AcceleratorBufferPerformanceCounters::LogHostDeviceCopySkipped();
1436 assert(std::is_trivially_copyable<T>::value);
1438 AcceleratorBufferPerformanceCounters::LogDeviceHostCopyBlocking();
1445 vk::PipelineStageFlagBits::eComputeShader,
1446 vk::PipelineStageFlagBits::eTransfer,
1449 vk::AccessFlagBits::eShaderWrite,
1450 vk::AccessFlagBits::eTransferRead),
1473 assert(std::is_trivially_copyable<T>::value);
1475 AcceleratorBufferPerformanceCounters::LogDeviceHostCopyBlocking();
1483 vk::PipelineStageFlagBits::eComputeShader,
1484 vk::PipelineStageFlagBits::eTransfer,
1487 vk::AccessFlagBits::eShaderWrite,
1488 vk::AccessFlagBits::eTransferRead),
1511 assert(std::is_trivially_copyable<T>::value);
1513 AcceleratorBufferPerformanceCounters::LogDeviceHostCopyNonBlocking();
1518 cmdBuf.pipelineBarrier(
1519 vk::PipelineStageFlagBits::eComputeShader,
1520 vk::PipelineStageFlagBits::eTransfer,
1523 vk::AccessFlagBits::eShaderWrite,
1524 vk::AccessFlagBits::eTransferRead
1546 assert(std::is_trivially_copyable<T>::value);
1548 AcceleratorBufferPerformanceCounters::LogHostDeviceCopyBlocking();
1577 assert(std::is_trivially_copyable<T>::value);
1579 AcceleratorBufferPerformanceCounters::LogHostDeviceCopyNonBlocking();
1590 cmdBuf.pipelineBarrier(
1591 vk::PipelineStageFlagBits::eTransfer,
1592 vk::PipelineStageFlagBits::eComputeShader,
1595 vk::AccessFlagBits::eTransferWrite,
1596 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite),
1608 cmdBuf.pipelineBarrier(
1609 vk::PipelineStageFlagBits::eTransfer,
1610 vk::PipelineStageFlagBits::eComputeShader,
1613 vk::AccessFlagBits::eTransferWrite,
1614 vk::AccessFlagBits::eShaderRead | vk::AccessFlagBits::eShaderWrite),
1678 LogWarning(
"Freeing a GPU buffer without any CPU backing, may cause data loss\n");
1702 LogFatal(
"AllocateCpuBuffer with size zero (invalid)\n");
1711 vk::BufferUsageFlagBits::eTransferSrc |
1712 vk::BufferUsageFlagBits::eTransferDst |
1713 vk::BufferUsageFlagBits::eStorageBuffer);
1760 char fname[] =
"/tmp/ngscopeclient-tmpXXXXXX";
1764 LogError(
"Failed to create temporary file %s\n",
fname);
1772 LogError(
"Failed to resize temporary file %s\n",
fname);
1786 LogError(
"Failed to map temporary file %s\n",
fname);
1794 LogWarning(
"Failed to unlink temporary file %s, file will remain after application terminates\n",
fname);
1801 if(!std::is_trivially_copyable<T>::value)
1819 if(!std::is_trivially_copyable<T>::value)
1831 case MEM_TYPE_CPU_DMA_CAPABLE:
1832 LogFatal(
"FreeCpuPointer for MEM_TYPE_CPU_DMA_CAPABLE requires the vk::raii::DeviceMemory\n");
1835 case MEM_TYPE_CPU_PAGED:
1843 case MEM_TYPE_CPU_ONLY:
1848 LogFatal(
"FreeCpuPointer: invalid type %x\n", type);
1864 case MEM_TYPE_CPU_DMA_CAPABLE:
1881 assert(std::is_trivially_copyable<T>::value);
1887 vk::BufferUsageFlagBits::eTransferSrc |
1888 vk::BufferUsageFlagBits::eTransferDst |
1889 vk::BufferUsageFlagBits::eStorageBuffer);
1905 catch(vk::OutOfDeviceMemoryError&
ex)
1920 catch(vk::OutOfDeviceMemoryError&
ex2)
1922 LogDebug(
"Allocation failed again\n");
1931 LogDebug(
"Final retry\n");
1937 catch(vk::OutOfDeviceMemoryError&
ex2)
1939 LogDebug(
"Allocation failed again\n");
1948 "Failed to allocate %s of GPU memory despite our best efforts to reclaim space, falling back to CPU-side pinned allocation\n",
1949 Unit(Unit::UNIT_BYTES).PrettyPrint(
req.size, 4).c_str());
1977 std::string
prefix = std::string(
"AcceleratorBuffer.") +
sname +
".";
1983 vk::DebugUtilsObjectNameInfoEXT(
1984 vk::ObjectType::eBuffer,
1989 vk::DebugUtilsObjectNameInfoEXT(
1990 vk::ObjectType::eDeviceMemory,
2004 std::string
prefix = std::string(
"AcceleratorBuffer.") +
sname +
".";
2010 vk::DebugUtilsObjectNameInfoEXT(
2011 vk::ObjectType::eBuffer,
2016 vk::DebugUtilsObjectNameInfoEXT(
2017 vk::ObjectType::eDeviceMemory,
2032 void SetName(
const std::string& name)
2056 LogFatal(
"failed to open debug dump %s\n",
fname.c_str());
2058 PrepareForCpuAccess();
2096 nvtx3::scoped_range
nrange(
"Dev/host busy wait");
2148 nvtx3::scoped_range
nrange(
"Host/dev busy wait");
2172 void ClearTransferFlags()
bool(* MemoryPressureHandler)(MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize)
Memory pressure handler type, called when free memory reaches a warning level or a Vulkan allocation ...
Definition AcceleratorBuffer.h:198
MemoryPressureLevel
Levels of memory pressure.
Definition AcceleratorBuffer.h:172
@ Hard
A memory allocation has failed and we need to free memory immediately to continue execution.
@ Soft
Free memory has reached a warning threshold.
bool OnMemoryPressure(MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize)
Called when we run low on memory.
Definition scopehal.cpp:1129
MemoryPressureType
Types of memory pressure.
Definition AcceleratorBuffer.h:189
@ Host
Pinned CPU-side memory.
std::set< MemoryPressureHandler > g_memoryPressureHandlers
List of handlers for low memory registered by various subsystems.
Definition scopehal.cpp:212
Declaration of AlignedAllocator.
Declaration of QueueManager and QueueHandle.
Base class for AcceleratorBuffer storing common metadata used by all derived types.
Definition AcceleratorBuffer.h:249
static std::recursive_mutex m_objectListMutex
Mutex controlling access to m_objectList.
Definition AcceleratorBuffer.h:309
size_t capacity() const
Returns the allocated size of the container.
Definition AcceleratorBuffer.h:290
const std::string & GetName() const
Returns the debug name of the buffer, if any.
Definition AcceleratorBuffer.h:294
static std::recursive_mutex & GetMutex()
Get the mutex for m_objectList.
Definition AcceleratorBuffer.h:317
std::string m_name
Friendly name of the buffer (for debug tools)
Definition AcceleratorBuffer.h:279
size_t size() const
Returns the actual size of the container (may be smaller than what was allocated)
Definition AcceleratorBuffer.h:286
size_t m_size
Size of the memory actually being used.
Definition AcceleratorBuffer.h:274
static std::set< AcceleratorBufferBase * > m_objectList
Set of all existing AcceleratorBufferBase objects.
Definition AcceleratorBuffer.h:312
virtual size_t GetElementSize() const =0
Gets the size of each entry in the container.
static const std::set< AcceleratorBufferBase * > & GetObjects()
Get the set of all objects. You must hold a lock on m_objectListMutex while working with it.
Definition AcceleratorBuffer.h:321
virtual std::string GetType() const =0
Gets the underlying C++ object type.
size_t m_capacity
Size of the allocated memory space (may be larger than m_size)
Definition AcceleratorBuffer.h:271
Definition AcceleratorBuffer.h:204
A buffer of memory which may be used by GPU acceleration.
Definition AcceleratorBuffer.h:343
std::unique_ptr< vk::raii::Event > m_deviceHostTransferEvent
Event signaled upon completion of a device-host transfer.
Definition AcceleratorBuffer.h:2118
std::unique_ptr< vk::raii::Buffer > m_gpuBuffer
Buffer object for GPU-side memory.
Definition AcceleratorBuffer.h:500
bool empty() const
Returns true if the container is empty.
Definition AcceleratorBuffer.h:610
T * m_cpuPtr
CPU-side mapped pointer.
Definition AcceleratorBuffer.h:488
__attribute__((noinline)) void CopyFrom(const std
Copies our content from a std::vector.
Definition AcceleratorBuffer.h:727
bool IsCpuBufferStale() const
Returns true if the CPU-side buffer is stale.
Definition AcceleratorBuffer.h:616
vk::DescriptorBufferInfo GetBufferInfo()
Returns a vk::DescriptorBufferInfo suitable for binding this object to.
Definition AcceleratorBuffer.h:665
std::unique_ptr< vk::raii::DeviceMemory > m_cpuPhysMem
CPU-side physical memory.
Definition AcceleratorBuffer.h:491
bool IsReachableFromCpu(MemoryType mt)
Returns true if the given buffer type can be reached from the CPU.
Definition AcceleratorBuffer.h:457
bool IsSingleSharedBuffer() const
Returns true if the object contains only a single buffer.
Definition AcceleratorBuffer.h:640
bool HasCpuBuffer() const
Returns true if there is currently a CPU-side buffer.
Definition AcceleratorBuffer.h:628
std::unique_ptr< vk::raii::DeviceMemory > m_gpuPhysMem
GPU-side physical memory.
Definition AcceleratorBuffer.h:494
bool m_gpuPhysMemIsStale
True if m_gpuPhysMem contains stale data (m_cpuPtr has been modified and they point to different memo...
Definition AcceleratorBuffer.h:509
bool IsReachableFromGpu(MemoryType mt)
Returns true if the given buffer type can be reached from the GPU.
Definition AcceleratorBuffer.h:463
vk::Buffer GetBuffer()
Returns the preferred buffer for GPU-side access.
Definition AcceleratorBuffer.h:648
std::atomic< bool > m_hostDeviceTransferActive
True if a host-device transfer has been submitted.
Definition AcceleratorBuffer.h:2167
size_t GetCpuMemoryBytes() const
Returns the total reserved CPU memory, in bytes.
Definition AcceleratorBuffer.h:588
size_t GetMemoryBytes() const
Returns the total size of the buffer (wherever it is), in bytes.
Definition AcceleratorBuffer.h:582
bool m_buffersAreSame
True if we have only one piece of physical memory accessible from both sides.
Definition AcceleratorBuffer.h:503
__attribute__((noinline)) AcceleratorBuffer(const std
Creates a new AcceleratorBuffer with no content.
Definition AcceleratorBuffer.h:540
void reserve(size_t size)
Reallocates buffers so that at least size elements of storage are available.
Definition AcceleratorBuffer.h:709
UsageHint m_gpuAccessHint
Hint about how likely future GPU access is.
Definition AcceleratorBuffer.h:531
MemoryType m_cpuMemoryType
Type of the CPU-side buffer.
Definition AcceleratorBuffer.h:479
bool IsFastFromGpu(MemoryType mt)
Returns true if the given buffer type is fast to access from the GPU.
Definition AcceleratorBuffer.h:475
std::unique_ptr< vk::raii::Event > m_hostDeviceTransferEvent
Event signaled upon completion of a host-device transfer.
Definition AcceleratorBuffer.h:2170
std::unique_ptr< vk::raii::Buffer > m_cpuBuffer
Buffer object for CPU-side memory.
Definition AcceleratorBuffer.h:497
MemoryType m_gpuMemoryType
Type of the GPU-side buffer.
Definition AcceleratorBuffer.h:482
bool HasGpuBuffer() const
Returns true if there is currently a GPU-side buffer.
Definition AcceleratorBuffer.h:634
size_t GetGpuMemoryBytes() const
Returns the total reserved GPU memory, in bytes.
Definition AcceleratorBuffer.h:599
int m_tempFileHandle
File handle used for MEM_TYPE_CPU_PAGED.
Definition AcceleratorBuffer.h:513
virtual std::string GetType() const
Gets the underlying C++ object type.
Definition AcceleratorBuffer.h:346
void shrink_to_fit()
Frees unused memory so that m_size == m_capacity.
Definition AcceleratorBuffer.h:718
bool IsFastFromCpu(MemoryType mt)
Returns true if the given buffer type is fast to access from the CPU.
Definition AcceleratorBuffer.h:469
bool BeginHostDeviceTransferIfNeeded()
Starts a host-to-device transfer if we need to do one.
Definition AcceleratorBuffer.h:2137
MemoryAttributes
Attributes that a memory buffer can have.
Definition AcceleratorBuffer.h:405
bool m_cpuPhysMemIsStale
True if m_cpuPtr contains stale data (m_gpuPhysMem has been modified and they point to different memo...
Definition AcceleratorBuffer.h:506
virtual size_t GetElementSize() const
Gets the size of each entry in the container.
Definition AcceleratorBuffer.h:386
__attribute__((noinline)) void CopyFrom(const AcceleratorBuffer< T > &rhs
Copies our content from another AcceleratorBuffer.
UsageHint m_cpuAccessHint
Hint about how likely future CPU access is.
Definition AcceleratorBuffer.h:528
MemoryType
Types of memory buffer.
Definition AcceleratorBuffer.h:423
T * GetCpuPointer()
Gets a pointer to the CPU-side buffer.
Definition AcceleratorBuffer.h:659
void clear()
Resize the container to be empty (but don't free memory)
Definition AcceleratorBuffer.h:703
bool IsGpuBufferStale() const
Returns true if the GPU-side buffer is stale.
Definition AcceleratorBuffer.h:622
void resize(size_t size, bool exactSize=false)
Change the usable size of the container.
Definition AcceleratorBuffer.h:679
Aligned memory allocator for STL containers.
Definition AlignedAllocator.h:53
void deallocate(T *const p, const size_t unused) const
Free a block of memory.
Definition AlignedAllocator.h:194
T * allocate(size_t n) const
Allocate a block of memory.
Definition AlignedAllocator.h:159
A unit of measurement, plus conversion to pretty-printed output.
Definition Unit.h:59
uint32_t g_vkPinnedMemoryType
Vulkan memory type for CPU-based memory that is also GPU-readable.
Definition VulkanInit.cpp:118
std::mutex g_vkTransferMutex
Mutex for interlocking access to g_vkTransferCommandBuffer and g_vkTransferCommandPool.
Definition VulkanInit.cpp:112
bool g_hasDebugUtils
Indicates whether the VK_EXT_debug_utils extension is available.
Definition VulkanInit.cpp:201
std::shared_ptr< vk::raii::Device > g_vkComputeDevice
The Vulkan device selected for compute operations (may or may not be same device as rendering)
Definition VulkanInit.cpp:71
std::unique_ptr< vk::raii::CommandBuffer > g_vkTransferCommandBuffer
Command buffer for AcceleratorBuffer transfers.
Definition VulkanInit.cpp:89
std::shared_ptr< QueueHandle > g_vkTransferQueue
Queue for AcceleratorBuffer transfers.
Definition VulkanInit.cpp:98
uint32_t g_vkLocalMemoryType
Vulkan memory type for GPU-based memory (generally not CPU-readable, except on unified memory systems...
Definition VulkanInit.cpp:124
bool g_vulkanDeviceHasUnifiedMemory
Indicates whether the Vulkan device is unified memory.
Definition VulkanInit.cpp:226