Skip to content

Thread safety question regarding concurrent access to VmaAllocator #525

@xeechou

Description

@xeechou

Hello, I am on the master and I create vmaAllocator with only flag VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT. Based on the documentation:

all calls to functions that take #VmaAllocator as first parameter are safe to call from multiple threads simultaneously because they aresynchronized internally when needed.

However I got quite a bit warning from thread sanitizer warning about data race. I don't know if this is false positive or not but I think I should report.

Here is the trace from thread sanitizer.

WARNING: ThreadSanitizer: data race (pid=79053)
  Write of size 8 at 0x00010b71fd30 by thread T36 (mutexes: write M0, write M1):
    #0 VmaDeviceMemoryBlock::Unmap(VmaAllocator_T*, unsigned int) vk_mem_alloc.h:10824 (libframework.dylib:arm64+0x220d90)
    #1 VmaAllocator_T::Unmap(VmaAllocation_T*) vk_mem_alloc.h:14645 (libframework.dylib:arm64+0x23895c)
    #2 vmaUnmapMemory vk_mem_alloc.h:15998 (libframework.dylib:arm64+0x23e0f4)
    #3 sp::vkm<vk::Buffer>::unmap_memory() vkm.cpp:396 (libframework.dylib:arm64+0x262fa8)
    #4 void sp::vkm<vk::Buffer>::map<int>(std::__1::function<void (int*)>, unsigned long) vkm.hh:137 (libextras.dylib:arm64+0xe2834)
    #5 sp::triangle_indices_manager::upload_all_entities()::$_0::operator()(vk::CommandBuffer, bool, sp::triangle_indices_manager::upload_all_entities()::ctx_t&) const triangle_indices.cc:292 (libextras.dylib:arm64+0xf58d8)
    ...
  Previous read of size 8 at 0x00010b71fd30 by thread T38:
    #0 VmaDeviceMemoryBlock::GetMappedData() const vk_mem_alloc.h:6314 (libframework.dylib:arm64+0x2232b0)
    #1 VmaBlockVector::AllocatePage(unsigned long long, unsigned long long, VmaAllocationCreateInfo const&, VmaSuballocationType, VmaAllocation_T**) vk_mem_alloc.h:11484 (libframework.dylib:arm64+0x2255e4)
    #2 VmaBlockVector::Allocate(unsigned long long, unsigned long long, VmaAllocationCreateInfo const&, VmaSuballocationType, unsigned long, VmaAllocation_T**) vk_mem_alloc.h:11381 (libframework.dylib:arm64+0x224f7c)
    #3 VmaAllocator_T::AllocateMemoryOfType(VmaPool_T*, unsigned long long, unsigned long long, bool, VkBuffer_T*, VkImage_T*, VmaBufferImageUsage, VmaAllocationCreateInfo const&, unsigned int, VmaSuballocationType, VmaDedicatedAllocationList&, VmaBlockVector&, unsigned long, VmaAllocation_T**) vk_mem_alloc.h:13592 (libframework.dylib:arm64+0x233ba8)
    #4 VmaAllocator_T::AllocateMemory(VkMemoryRequirements const&, bool, bool, VkBuffer_T*, VkImage_T*, VmaBufferImageUsage, VmaAllocationCreateInfo const&, VmaSuballocationType, unsigned long, VmaAllocation_T**) vk_mem_alloc.h:14111 (libframework.dylib:arm64+0x2366b4)
    #5 vmaCreateBuffer vk_mem_alloc.h:16302 (libframework.dylib:arm64+0x23f594)
    #6 sp::create_staging_buffer misc.cpp:243 (libframework.dylib:arm64+0xf36d8)
    #7 data_provider::on_batch_resolve const data.cc:222 (visibility_batch:arm64+0x100096d94)
    ...
  Location is heap block of size 296 at 0x00010b71fcc0 allocated by thread T34:
    #0 posix_memalign <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x60988)
    #1 vma_aligned_alloc(unsigned long, unsigned long) vk_mem_alloc.h:3061 (libframework.dylib:arm64+0x264c58)
    #2 VmaMalloc(VkAllocationCallbacks const*, unsigned long, unsigned long) vk_mem_alloc.h:4171 (libframework.dylib:arm64+0x264b60)
    #3 VmaMalloc(VmaAllocator_T*, unsigned long, unsigned long) vk_mem_alloc.h:10614 (libframework.dylib:arm64+0x26e344)
    #4 VmaDeviceMemoryBlock* VmaAllocate<VmaDeviceMemoryBlock>(VmaAllocator_T*) vk_mem_alloc.h:10625 (libframework.dylib:arm64+0x228244)
    #5 VmaBlockVector::CreateBlock(unsigned long long, unsigned long*) vk_mem_alloc.h:11864 (libframework.dylib:arm64+0x22474c)
    #6 VmaBlockVector::AllocatePage(unsigned long long, unsigned long long, VmaAllocationCreateInfo const&, VmaSuballocationType, VmaAllocation_T**) vk_mem_alloc.h:11564 (libframework.dylib:arm64+0x225a90)
    #7 VmaBlockVector::Allocate(unsigned long long, unsigned long long, VmaAllocationCreateInfo const&, VmaSuballocationType, unsigned long, VmaAllocation_T**) vk_mem_alloc.h:11381 (libframework.dylib:arm64+0x224f7c)
    #8 VmaAllocator_T::AllocateMemoryOfType(VmaPool_T*, unsigned long long, unsigned long long, bool, VkBuffer_T*, VkImage_T*, VmaBufferImageUsage, VmaAllocationCreateInfo const&, unsigned int, VmaSuballocationType, VmaDedicatedAllocationList&, VmaBlockVector&, unsigned long, VmaAllocation_T**) vk_mem_alloc.h:13592 (libframework.dylib:arm64+0x233ba8)
    #9 VmaAllocator_T::AllocateMemory(VkMemoryRequirements const&, bool, bool, VkBuffer_T*, VkImage_T*, VmaBufferImageUsage, VmaAllocationCreateInfo const&, VmaSuballocationType, unsigned long, VmaAllocation_T**) vk_mem_alloc.h:14111 (libframework.dylib:arm64+0x2366b4)
    #10 vmaCreateBuffer vk_mem_alloc.h:16302 (libframework.dylib:arm64+0x23f594)
    #11 sp::create_staging_buffe misc.cpp:243 (libframework.dylib:arm64+0xf36d8)
    #12 sp::instance_manager::upload_all_entities const instances.cc:270 (libextras.dylib:arm64+0xae538)
    ...

BTW, the create_staging_buffer() function is like this:

vkm<vk::Buffer>
create_staging_buffer(device_data&       dev,
                      size_t             size,
                      const void*        data,
                      const std::string& name)
{
    vk::Buffer              res;
    VmaAllocation           alloc;
    vk::BufferCreateInfo    staging_info({},
                                      size,
                                      vk::BufferUsageFlagBits::eTransferSrc,
                                      vk::SharingMode::eExclusive);
    VmaAllocationCreateInfo alloc_info = {};
    alloc_info.usage                   = VMA_MEMORY_USAGE_AUTO;
    alloc_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;

    vmaCreateBuffer(dev.allocator,
                    (VkBufferCreateInfo*)&staging_info,
                    &alloc_info,
                    reinterpret_cast<VkBuffer*>(&res),
                    &alloc,
                    nullptr);

    if (data)
    {
        void* mem = nullptr;
        vmaMapMemory(dev.allocator, alloc, &mem);
        memcpy(mem, data, size);
        vmaUnmapMemory(dev.allocator, alloc);
    }
    return vkm<vk::Buffer>(dev, res, alloc, name);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions