2016-02-10 11:52:42 -06:00
|
|
|
|
|
|
|
|
#include "hc_am.hpp"
|
|
|
|
|
#include "hsa.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "hcc_detail/AM.h" // TODO - Remove me.
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
#define DB_TRACKER 0
|
|
|
|
|
#define MUTEX_LOCK 1
|
2016-02-10 11:52:42 -06:00
|
|
|
|
|
|
|
|
#if DB_TRACKER
|
|
|
|
|
#define mprintf( ...) {\
|
|
|
|
|
fprintf (stderr, __VA_ARGS__);\
|
|
|
|
|
};
|
|
|
|
|
#else
|
|
|
|
|
#define mprintf( ...)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//=========================================================================================================
|
|
|
|
|
// Pointer Tracker Structures:
|
|
|
|
|
//=========================================================================================================
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
//#include <shared_mutex>
|
|
|
|
|
|
|
|
|
|
struct AmMemoryRange {
|
|
|
|
|
void * _basePointer;
|
|
|
|
|
void * _endPointer;
|
|
|
|
|
AmMemoryRange(void *basePointer, size_t sizeBytes) :
|
|
|
|
|
_basePointer(basePointer), _endPointer((unsigned char*)basePointer + sizeBytes - 1) {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Functor to compare ranges:
|
|
|
|
|
struct AmMemoryRangeCompare {
|
|
|
|
|
// Return true is LHS range is less than RHS - used to order the
|
|
|
|
|
bool operator()(const AmMemoryRange &lhs, const AmMemoryRange &rhs) const
|
|
|
|
|
{
|
|
|
|
|
return lhs._endPointer < rhs._basePointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &os, const hc::AmPointerInfo &ap)
|
|
|
|
|
{
|
|
|
|
|
os << "hostPointer:" << ap._hostPointer << " devicePointer:"<< ap._devicePointer << " sizeBytes:" << ap._sizeBytes
|
2016-02-11 22:03:01 -06:00
|
|
|
<< " isInDeviceMem:" << ap._isInDeviceMem << " isAmManaged:" << ap._isAmManaged
|
|
|
|
|
<< " appId:" << ap._appId << " appAllocFlags:" << ap._appAllocationFlags;
|
2016-02-10 11:52:42 -06:00
|
|
|
return os;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
//-------------------------------------------------------------------------------------------------
|
2016-02-10 11:52:42 -06:00
|
|
|
// This structure tracks information for each pointer.
|
2016-02-11 22:03:01 -06:00
|
|
|
// Uses memory-range-based lookups - so pointers that exist anywhere in the range of hostPtr + size
|
|
|
|
|
// will find the associated AmPointerInfo.
|
2016-02-10 11:52:42 -06:00
|
|
|
// The insertions and lookups use a self-balancing binary tree and should support O(logN) lookup speed.
|
|
|
|
|
// The structure is thread-safe - writers obtain a mutex before modifying the tree. Multiple simulatenous readers are supported.
|
|
|
|
|
class AmPointerTracker {
|
|
|
|
|
typedef std::map<AmMemoryRange, hc::AmPointerInfo, AmMemoryRangeCompare> MapTrackerType;
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
void insert(void *pointer, const hc::AmPointerInfo &p);
|
|
|
|
|
int remove(void *pointer);
|
|
|
|
|
|
|
|
|
|
MapTrackerType::iterator find(void *hostPtr);
|
|
|
|
|
|
|
|
|
|
MapTrackerType::iterator end() { return _tracker.end(); };
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
size_t reset (hc::accelerator acc);
|
|
|
|
|
|
2016-02-10 11:52:42 -06:00
|
|
|
std::ostream & print (std::ostream &os);
|
|
|
|
|
private:
|
2016-02-11 22:03:01 -06:00
|
|
|
// TODO - use or remove.
|
|
|
|
|
inline void writeLock();
|
|
|
|
|
inline void writeUnlock();
|
|
|
|
|
inline void readLock();
|
|
|
|
|
inline void readUnlock();
|
|
|
|
|
|
2016-02-10 11:52:42 -06:00
|
|
|
MapTrackerType _tracker;
|
2016-02-11 22:03:01 -06:00
|
|
|
std::mutex _mutex;
|
2016-02-10 11:52:42 -06:00
|
|
|
//std::shared_timed_mutex _mut;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
void AmPointerTracker::insert (void *pointer, const hc::AmPointerInfo &p)
|
|
|
|
|
{
|
2016-02-11 22:03:01 -06:00
|
|
|
std::lock_guard<std::mutex> l (_mutex);
|
|
|
|
|
|
2016-02-10 11:52:42 -06:00
|
|
|
mprintf ("insert: %p + %zu\n", pointer, p._sizeBytes);
|
|
|
|
|
_tracker.insert(std::make_pair(AmMemoryRange(pointer, p._sizeBytes), p));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// Return 1 if removed or 0 if not found.
|
|
|
|
|
int AmPointerTracker::remove (void *pointer)
|
|
|
|
|
{
|
|
|
|
|
// TODO-mutex - write lock.
|
2016-02-11 22:03:01 -06:00
|
|
|
std::lock_guard<std::mutex> l (_mutex);
|
2016-02-10 11:52:42 -06:00
|
|
|
mprintf ("remove: %p\n", pointer);
|
|
|
|
|
return _tracker.erase(AmMemoryRange(pointer,1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
AmPointerTracker::MapTrackerType::iterator AmPointerTracker::find (void *pointer)
|
|
|
|
|
{
|
|
|
|
|
// TODO-mutex- read lock
|
2016-02-11 22:03:01 -06:00
|
|
|
std::lock_guard<std::mutex> l (_mutex);
|
2016-02-10 11:52:42 -06:00
|
|
|
auto iter = _tracker.find(AmMemoryRange(pointer,1));
|
|
|
|
|
mprintf ("find: %p\n", pointer);
|
|
|
|
|
return iter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
//---
|
2016-02-10 11:52:42 -06:00
|
|
|
std::ostream & AmPointerTracker::print (std::ostream &os)
|
|
|
|
|
{
|
2016-02-11 22:03:01 -06:00
|
|
|
std::lock_guard<std::mutex> l (_mutex);
|
2016-02-10 11:52:42 -06:00
|
|
|
for (auto iter = _tracker.begin() ; iter != _tracker.end(); iter++) {
|
|
|
|
|
os << " " << iter->first._basePointer << "..." << iter->first._endPointer << ":: ";
|
|
|
|
|
os << iter->second << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return os;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
//---
|
|
|
|
|
// Remove all tracked locations, and free the associated memory (if the range was originally allocated by AM).
|
|
|
|
|
// Returns count of ranges removed.
|
|
|
|
|
size_t AmPointerTracker::reset (hc::accelerator acc)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> l (_mutex);
|
|
|
|
|
mprintf ("reset: \n");
|
|
|
|
|
|
|
|
|
|
size_t count = 0;
|
|
|
|
|
// relies on C++11 (erase returns iterator)
|
|
|
|
|
for (auto iter = _tracker.begin() ; iter != _tracker.end(); ) {
|
|
|
|
|
if (iter->second._acc == acc) {
|
|
|
|
|
if (iter->second._isAmManaged) {
|
|
|
|
|
hsa_memory_free(iter->first._basePointer);
|
|
|
|
|
}
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
|
|
iter = _tracker.erase(iter);
|
|
|
|
|
} else {
|
|
|
|
|
iter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
void AmPointerTracker::writeLock ()
|
|
|
|
|
{
|
|
|
|
|
_mutex.lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
void AmPointerTracker::writeUnlock ()
|
|
|
|
|
{
|
|
|
|
|
_mutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// TODO - support multiple concurrent reader
|
|
|
|
|
void AmPointerTracker::readLock ()
|
|
|
|
|
{
|
|
|
|
|
_mutex.lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
// TODO - support multiple concurrent reader
|
|
|
|
|
void AmPointerTracker::readUnlock ()
|
|
|
|
|
{
|
|
|
|
|
_mutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-02-10 11:52:42 -06:00
|
|
|
|
|
|
|
|
//=========================================================================================================
|
|
|
|
|
// Global var defs:
|
|
|
|
|
//=========================================================================================================
|
|
|
|
|
AmPointerTracker g_amPointerTracker; // Track all am pointer allocations.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================================================================
|
|
|
|
|
// API Definitions.
|
|
|
|
|
//=========================================================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
namespace hc {
|
|
|
|
|
|
|
|
|
|
// Allocate accelerator memory, return NULL if memory could not be allocated:
|
|
|
|
|
auto_voidp AM_alloc(size_t sizeBytes, hc::accelerator acc, unsigned flags)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
void *ptr = NULL;
|
|
|
|
|
|
|
|
|
|
if (sizeBytes != 0 ) {
|
|
|
|
|
if (acc.is_hsa_accelerator()) {
|
|
|
|
|
hsa_agent_t *hsa_agent = static_cast<hsa_agent_t*> (acc.get_default_view().get_hsa_agent());
|
|
|
|
|
hsa_region_t *alloc_region;
|
|
|
|
|
if (flags & amHostPinned) {
|
|
|
|
|
alloc_region = static_cast<hsa_region_t*>(acc.get_hsa_am_system_region());
|
|
|
|
|
} else {
|
|
|
|
|
alloc_region = static_cast<hsa_region_t*>(acc.get_hsa_am_region());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (alloc_region->handle != -1) {
|
|
|
|
|
|
|
|
|
|
hsa_status_t s1 = hsa_memory_allocate(*alloc_region, sizeBytes, &ptr);
|
|
|
|
|
hsa_status_t s2 = hsa_memory_assign_agent(ptr, *hsa_agent, HSA_ACCESS_PERMISSION_RW);
|
|
|
|
|
|
|
|
|
|
if ((s1 != HSA_STATUS_SUCCESS) || (s2 != HSA_STATUS_SUCCESS)) {
|
|
|
|
|
ptr = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
if (flags & amHostPinned) {
|
|
|
|
|
g_amPointerTracker.insert(ptr,
|
2016-02-11 22:03:01 -06:00
|
|
|
hc::AmPointerInfo(ptr/*hostPointer*/, ptr /*devicePointer*/, sizeBytes, acc, false/*isDevice*/, true /*isAMManaged*/));
|
2016-02-10 11:52:42 -06:00
|
|
|
} else {
|
|
|
|
|
g_amPointerTracker.insert(ptr,
|
2016-02-11 22:03:01 -06:00
|
|
|
hc::AmPointerInfo(NULL/*hostPointer*/, ptr /*devicePointer*/, sizeBytes, acc, true/*isDevice*/, true /*isAMManaged*/));
|
2016-02-10 11:52:42 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
am_status_t AM_free(void* ptr)
|
|
|
|
|
{
|
|
|
|
|
am_status_t status = AM_SUCCESS;
|
|
|
|
|
|
|
|
|
|
if (ptr != NULL) {
|
2016-02-11 22:03:01 -06:00
|
|
|
// See also tracker::reset which can free memory.
|
2016-02-10 11:52:42 -06:00
|
|
|
hsa_memory_free(ptr);
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
int numRemoved = g_amPointerTracker.remove(ptr) ;
|
2016-02-10 11:52:42 -06:00
|
|
|
if (numRemoved == 0) {
|
|
|
|
|
status = AM_ERROR_MISC;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
am_status_t AM_copy(void* dst, const void* src, size_t sizeBytes)
|
|
|
|
|
{
|
|
|
|
|
am_status_t am_status = AM_ERROR_MISC;
|
|
|
|
|
hsa_status_t err = hsa_memory_copy(dst, src, sizeBytes);
|
|
|
|
|
|
|
|
|
|
if (err == HSA_STATUS_SUCCESS) {
|
|
|
|
|
am_status = AM_SUCCESS;
|
|
|
|
|
} else {
|
|
|
|
|
am_status = AM_ERROR_MISC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return am_status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
am_status_t am_memtracker_getinfo(hc::AmPointerInfo *info, void *ptr)
|
2016-02-10 11:52:42 -06:00
|
|
|
{
|
|
|
|
|
auto infoI = g_amPointerTracker.find(ptr);
|
|
|
|
|
if (infoI != g_amPointerTracker.end()) {
|
|
|
|
|
*info = infoI->second;
|
|
|
|
|
return AM_SUCCESS;
|
|
|
|
|
} else {
|
|
|
|
|
return AM_ERROR_MISC;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
|
|
|
|
|
am_status_t am_memtracker_update(void* ptr, int appId, unsigned allocationFlags);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
am_status_t am_memtracker_add(void* ptr, size_t sizeBytes, hc::accelerator acc, bool isDeviceMem)
|
|
|
|
|
{
|
|
|
|
|
if (isDeviceMem) {
|
|
|
|
|
g_amPointerTracker.insert(ptr, hc::AmPointerInfo(ptr/*hostPointer*/, ptr /*devicePointer*/, sizeBytes, acc, true/*isDevice*/, false /*isAMManaged*/));
|
|
|
|
|
} else {
|
|
|
|
|
g_amPointerTracker.insert(ptr, hc::AmPointerInfo(NULL/*hostPointer*/, ptr /*devicePointer*/, sizeBytes, acc, false/*isDevice*/, false /*isAMManaged*/));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AM_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
am_status_t am_memtracker_remove(void* ptr)
|
|
|
|
|
{
|
|
|
|
|
am_status_t status = AM_SUCCESS;
|
|
|
|
|
|
|
|
|
|
int numRemoved = g_amPointerTracker.remove(ptr) ;
|
|
|
|
|
if (numRemoved == 0) {
|
|
|
|
|
status = AM_ERROR_MISC;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
|
void am_memtracker_print()
|
2016-02-10 11:52:42 -06:00
|
|
|
{
|
|
|
|
|
g_amPointerTracker.print(std::cerr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-11 22:03:01 -06:00
|
|
|
//---
|
|
|
|
|
size_t am_memtracker_reset(hc::accelerator acc)
|
|
|
|
|
{
|
|
|
|
|
return g_amPointerTracker.reset(acc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-02-10 11:52:42 -06:00
|
|
|
} // end namespace hc.
|