Skip to content

[Issue]: Releasing virtual address regions fails when several memory regions mapped via hipMemMap are unmaped with one call to hipMemUnmap #285

Open
@IMbackK

Description

@IMbackK

Problem Description

When multiple memory regions are mapped to a virtual address space via hipMemMap and then unmapped via a single call to hipMemUnmap, hipMemAddressFree will fail as rocr will consider there to still be another user of that region, even when all memory has been unmaped.

in this case hipMemAddressFree will ultimately fail here as it->second.use_count is > 0:
https://github.com/ROCm/ROCR-Runtime/blob/8b6b9c140d0ec01f73b69348eb53206eea5d5e50/runtime/hsa-runtime/core/runtime/runtime.cpp#L3092C7-L3092C27

reproducer:

#include <hip/hip_runtime.h>
#include <stdio.h>

#define HIP_CHECK(fn) { hipError_t err = fn; if(err != hipSuccess){fprintf(stderr, "Error: %s: %s at %d\n", hipGetErrorName(err), hipGetErrorString(err), __LINE__);} }

int main()
{
	size_t granularity;
	hipMemAllocationProp alloc_prop = {};
	alloc_prop.type = hipMemAllocationTypePinned;
	alloc_prop.location.type = hipMemLocationTypeDevice;
	alloc_prop.location.id = 0;
	HIP_CHECK(hipMemGetAllocationGranularity(&granularity, &alloc_prop, hipMemAllocationGranularityRecommended));
	printf("Device recommended granularity %zu\n", granularity);
	
	constexpr size_t maxSize = 1ull << 35; // 32 GB
	hipDeviceptr_t pool_addr = 0;
	HIP_CHECK(hipMemAddressReserve(&pool_addr, maxSize, 0, 0, 0));
	printf("reserved pool at %p\n", pool_addr);
	
	hipMemAllocationProp prop = {};
	prop.type = hipMemAllocationTypePinned;
	prop.location.type = hipMemLocationTypeDevice;
	prop.location.id = 0;
	hipMemGenericAllocationHandle_t handle;
	
	size_t pool_size = 0;
	HIP_CHECK(hipMemCreate(&handle, granularity, &prop, 0));
	HIP_CHECK(hipMemMap(static_cast<char*>(pool_addr) + pool_size, granularity, 0, handle, 0));
	HIP_CHECK(hipMemRelease(handle));
	pool_size += granularity;
	
	HIP_CHECK(hipMemCreate(&handle, granularity, &prop, 0));
	HIP_CHECK(hipMemMap(static_cast<char*>(pool_addr) + pool_size, granularity, 0, handle, 0));
	HIP_CHECK(hipMemRelease(handle));
	pool_size += granularity;
	
	HIP_CHECK(hipMemCreate(&handle, granularity, &prop, 0));
	HIP_CHECK(hipMemMap(static_cast<char*>(pool_addr) + pool_size, granularity, 0, handle, 0));
	HIP_CHECK(hipMemRelease(handle));
	pool_size += granularity;
	
	printf("unmapping %zu at %p\n", pool_size, pool_addr);
	HIP_CHECK(hipMemUnmap(pool_addr, pool_size));
	printf("Freeing virtual space %zu at %p\n", maxSize, pool_addr);
	HIP_CHECK(hipMemAddressFree(pool_addr, maxSize));
	
	return 0;
}

Output:

Device recommended granularity 4096
reserved pool at 0x73415fe00000
unmapping 12288 at 0x73415fe00000
Freeing virtual space 34359738368 at 0x73415fe00000
Error: hipErrorUnknown: unknown error at 46

Meanwhile this will work:

#include <hip/hip_runtime.h>
#include <stdio.h>

#define HIP_CHECK(fn) { hipError_t err = fn; if(err != hipSuccess){fprintf(stderr, "Error: %s: %s at %d\n", hipGetErrorName(err), hipGetErrorString(err), __LINE__);} }

int main()
{
	size_t granularity;
	hipMemAllocationProp alloc_prop = {};
	alloc_prop.type = hipMemAllocationTypePinned;
	alloc_prop.location.type = hipMemLocationTypeDevice;
	alloc_prop.location.id = 0;
	HIP_CHECK(hipMemGetAllocationGranularity(&granularity, &alloc_prop, hipMemAllocationGranularityRecommended));
	printf("Device recommended granularity %zu\n", granularity);
	
	constexpr size_t maxSize = 1ull << 35; // 32 GB
	hipDeviceptr_t pool_addr = 0;
	HIP_CHECK(hipMemAddressReserve(&pool_addr, maxSize, 0, 0, 0));
	printf("reserved pool at %p\n", pool_addr);
	
	hipMemAllocationProp prop = {};
	prop.type = hipMemAllocationTypePinned;
	prop.location.type = hipMemLocationTypeDevice;
	prop.location.id = 0;
	hipMemGenericAllocationHandle_t handle;
	
	size_t pool_size = 0;
	HIP_CHECK(hipMemCreate(&handle, granularity, &prop, 0));
	HIP_CHECK(hipMemMap(static_cast<char*>(pool_addr) + pool_size, granularity, 0, handle, 0));
	HIP_CHECK(hipMemUnmap(static_cast<char*>(pool_addr) + pool_size, granularity));
	HIP_CHECK(hipMemRelease(handle));
	pool_size += granularity;
	
	HIP_CHECK(hipMemCreate(&handle, granularity, &prop, 0));
	HIP_CHECK(hipMemMap(static_cast<char*>(pool_addr) + pool_size, granularity, 0, handle, 0));
	HIP_CHECK(hipMemUnmap(static_cast<char*>(pool_addr) + pool_size, granularity));
	HIP_CHECK(hipMemRelease(handle));
	pool_size += granularity;
	
	HIP_CHECK(hipMemCreate(&handle, granularity, &prop, 0));
	HIP_CHECK(hipMemMap(static_cast<char*>(pool_addr) + pool_size, granularity, 0, handle, 0));
	HIP_CHECK(hipMemUnmap(static_cast<char*>(pool_addr) + pool_size, granularity));
	HIP_CHECK(hipMemRelease(handle));
	pool_size += granularity;
	
	printf("unmapping %zu at %p\n", pool_size, pool_addr);
	//HIP_CHECK(hipMemUnmap(pool_addr, pool_size));
	printf("Freeing virtual space %zu at %p\n", maxSize, pool_addr);
	HIP_CHECK(hipMemAddressFree(pool_addr, maxSize));
	
	return 0;
}

Operating System

Ubuntu 24.04

CPU

Epyc 7552

GPU

MI100, RX 6800 XT

ROCm Version

ROCm 6.3.0

ROCm Component

ROCR-Runtime, clr

Steps to Reproduce

Run the repoducer

(Optional for Linux users) Output of /opt/rocm/bin/rocminfo --support

No response

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions