Split ihipCtx_t into ihipCtx_t and ihipDevice_t .

Major change to existing code base.
    Ctx holds streams, enables peers, and flags.
    Device holds accelerator, hsa-agent, device props.

Add hipCtx_t.

Add peer APIs that accept hipCtx_t (in addition to deviceId)

Compiles and passes directed tests.

Change-Id: Iddab1eb9edbf90caad2ef5959c6b811d658197f1


[ROCm/hip commit: cfdacab32f]
This commit is contained in:
Ben Sander
2016-08-08 11:55:57 -05:00
parent 1f9d2201fe
commit 57df8a3967
7 changed files with 687 additions and 531 deletions
+102 -68
View File
@@ -69,6 +69,7 @@ extern int HIP_DISABLE_HW_COPY_DEP;
extern thread_local int tls_defaultDevice;
extern thread_local hipError_t tls_lastHipError;
class ihipStream_t;
class ihipDevice_t;
class ihipCtx_t;
@@ -90,7 +91,7 @@ class ihipCtx_t;
#define STREAM_THREAD_SAFE 1
#define DEVICE_THREAD_SAFE 1
#define CTX_THREAD_SAFE 1
// If FORCE_COPY_DEP=1 , HIP runtime will add
// synchronization for copy commands in the same stream, regardless of command type.
@@ -227,7 +228,6 @@ public:
extern "C" {
#endif
typedef class ihipStream_t* hipStream_t;
#ifdef __cplusplus
}
@@ -287,10 +287,11 @@ typedef std::mutex StreamMutex;
typedef FakeMutex StreamMutex;
#endif
#if DEVICE_THREAD_SAFE
typedef std::mutex DeviceMutex;
// Pair Device and Ctx together, these could also be toggled separately if desired.
#if CTX_THREAD_SAFE
typedef std::mutex CtxMutex;
#else
typedef FakeMutex DeviceMutex;
typedef FakeMutex CtxMutex;
#warning "Device thread-safe disabled"
#endif
@@ -429,7 +430,8 @@ typedef uint64_t SeqNum_t ;
//-- Non-racy accessors:
// These functions access fields set at initialization time and are non-racy (so do not acquire mutex)
ihipCtx_t * getDevice() const;
const ihipDevice_t * getDevice() const;
ihipCtx_t * getCtx() const;
public:
@@ -440,21 +442,22 @@ public:
unsigned _flags;
private:
// Critical Data. THis MUST be accessed through LockedAccessor_StreamCrit_t
ihipStreamCritical_t _criticalData;
private:
void enqueueBarrier(hsa_queue_t* queue, ihipSignal_t *depSignal, ihipSignal_t *completionSignal);
void waitCopy(LockedAccessor_StreamCrit_t &crit, ihipSignal_t *signal);
void enqueueBarrier(hsa_queue_t* queue, ihipSignal_t *depSignal, ihipSignal_t *completionSignal);
void waitCopy(LockedAccessor_StreamCrit_t &crit, ihipSignal_t *signal);
// The unsigned return is hipMemcpyKind
unsigned resolveMemcpyDirection(bool srcTracked, bool dstTracked, bool srcInDeviceMem, bool dstInDeviceMem);
void setAsyncCopyAgents(unsigned kind, ihipCommand_t *commandType, hsa_agent_t *srcAgent, hsa_agent_t *dstAgent);
void setAsyncCopyAgents(unsigned kind, ihipCommand_t *commandType, hsa_agent_t *srcAgent, hsa_agent_t *dstAgent);
private: // Data
// Critical Data. THis MUST be accessed through LockedAccessor_StreamCrit_t
ihipStreamCritical_t _criticalData;
ihipCtx_t *_ctx; // parent context that owns this stream.
// Friends:
friend std::ostream& operator<<(std::ostream& os, const ihipStream_t& s);
};
@@ -507,117 +510,145 @@ struct ihipEvent_t {
//---
// Data that must be protected with thread-safe access
// All members are private - this class must be accessed through friend LockedAccessor which
// will lock the mutex on construction and unlock on destruction.
//
// MUTEX_TYPE is template argument so can easily convert to FakeMutex for performance or stress testing.
template <class MUTEX_TYPE>
class ihipDeviceCriticalBase_t : LockedBase<MUTEX_TYPE>
//----
// Properties of the HIP device.
// Multiple contexts can point to same device.
class ihipDevice_t
{
public:
ihipDeviceCriticalBase_t() : _stream_id(0), _peerAgents(nullptr) {};
void init(unsigned deviceCnt) {
assert(_peerAgents == nullptr);
ihipDevice_t(unsigned deviceIndex, unsigned deviceCnt, hc::accelerator &acc);
~ihipDevice_t();
// Accessors:
ihipCtx_t *getPrimaryCtx() const { return _primaryCtx; };
public:
unsigned _device_index; // device ID
hc::accelerator _acc;
hsa_agent_t _hsa_agent; // hsa agent handle
//! Number of compute units supported by the device:
unsigned _compute_units;
hipDeviceProp_t _props; // saved device properties.
StagingBuffer *_staging_buffer[2]; // one buffer for each direction.
int isLargeBar;
ihipCtx_t *_primaryCtx;
private:
hipError_t initProperties(hipDeviceProp_t* prop);
};
//=============================================================================
//=============================================================================
//class ihipCtxCriticalBase_t
template <typename MUTEX_TYPE>
class ihipCtxCriticalBase_t : LockedBase<MUTEX_TYPE>
{
public:
ihipCtxCriticalBase_t(unsigned deviceCnt) :
_peerCnt(0)
{
_peerAgents = new hsa_agent_t[deviceCnt];
};
~ihipDeviceCriticalBase_t() {
~ihipCtxCriticalBase_t() {
if (_peerAgents != nullptr) {
delete _peerAgents;
_peerAgents = nullptr;
}
_peerCnt = 0;
}
friend class LockedAccessor<ihipDeviceCriticalBase_t>;
// Streams:
void addStream(ihipStream_t *stream);
std::list<ihipStream_t*> &streams() { return _streams; };
const std::list<ihipStream_t*> &const_streams() const { return _streams; };
// "Allocate" a stream ID:
ihipStream_t::SeqNum_t incStreamId() { return _stream_id++; };
// Peer Accessor classes:
bool isPeer(const ihipCtx_t *peer); // returns Trus if peer has access to memory physically located on this device.
bool addPeer(ihipCtx_t *peer);
bool removePeer(ihipCtx_t *peer);
void resetPeers(ihipCtx_t *thisDevice);
void addStream(ihipStream_t *stream);
uint32_t peerCnt() const { return _peerCnt; };
hsa_agent_t *peerAgents() const { return _peerAgents; };
private:
//std::list< std::shared_ptr<ihipStream_t> > _streams; // streams associated with this device. TODO - convert to shared_ptr.
std::list< ihipStream_t* > _streams; // streams associated with this device.
ihipStream_t::SeqNum_t _stream_id;
friend class LockedAccessor<ihipCtxCriticalBase_t>;
private:
//--- Stream Tracker:
std::list< ihipStream_t* > _streams; // streams associated with this device.
//--- Peer Tracker:
// These reflect the currently Enabled set of peers for this GPU:
// Enabled peers have permissions to access the memory physically allocated on this device.
std::list<ihipCtx_t*> _peers; // list of enabled peer devices.
std::list<ihipCtx_t*> _peers; // list of enabled peer devices.
uint32_t _peerCnt; // number of enabled peers
hsa_agent_t *_peerAgents; // efficient packed array of enabled agents (to use for allocations.)
private:
void recomputePeerAgents();
};
// Note Mutex selected based on DeviceMutex
typedef ihipDeviceCriticalBase_t<DeviceMutex> ihipDeviceCritical_t;
// Note Mutex type Real/Fake selected based on CtxMutex
typedef ihipCtxCriticalBase_t<CtxMutex> ihipCtxCritical_t;
// This type is used by functions that need access to the critical device structures.
typedef LockedAccessor<ihipDeviceCritical_t> LockedAccessor_DeviceCrit_t;
typedef LockedAccessor<ihipCtxCritical_t> LockedAccessor_CtxCrit_t;
//=============================================================================
//-------------------------------------------------------------------------------------------------
// Functions which read or write the critical data are named locked_.
// ihipCtx_t does not use recursive locks so the ihip implementation must avoid calling a locked_ function from within a locked_ function.
// External functions which call several locked_ functions will acquire and release the lock for each function. if this occurs in
// performance-sensitive code we may want to refactor by adding non-locked functions and creating a new locked_ member function to call them all.
//=============================================================================
//class ihipCtx_t:
// A HIP CTX (context) points at one of the existing devices and contains the streams,
// peer-to-peer mappings, creation flags. Multiple contexts can point to the same
// device.
//
class ihipCtx_t
{
public: // Functions:
ihipCtx_t() {}; // note: calls constructor for _criticalData
void init(unsigned device_index, unsigned deviceCnt, hc::accelerator &acc, unsigned flags);
ihipCtx_t(const ihipDevice_t *device, unsigned deviceCnt, unsigned flags); // note: calls constructor for _criticalData
~ihipCtx_t();
// Functions which read or write the critical data are named locked_.
// ihipCtx_t does not use recursive locks so the ihip implementation must avoid calling a locked_ function from within a locked_ function.
// External functions which call several locked_ functions will acquire and release the lock for each function. if this occurs in
// performance-sensitive code we may want to refactor by adding non-locked functions and creating a new locked_ member function to call them all.
void locked_addStream(ihipStream_t *s);
void locked_removeStream(ihipStream_t *s);
void locked_reset();
void locked_waitAllStreams();
void locked_syncDefaultStream(bool waitOnSelf);
ihipDeviceCritical_t &criticalData() { return _criticalData; }; // TODO, move private. Fix P2P.
ihipCtxCritical_t &criticalData() { return _criticalData; }; // TODO, move private. Fix P2P.
public: // Data, set at initialization:
unsigned _device_index; // device ID
const ihipDevice_t *getDevice() const { return _device; };
hipDeviceProp_t _props; // saved device properties.
hc::accelerator _acc;
hsa_agent_t _hsa_agent; // hsa agent handle
// TODO - review uses of getWriteableDevice(), can these be converted to getDevice()
ihipDevice_t *getWriteableDevice() const { return const_cast<ihipDevice_t*> (_device); };
public: // Data
// The NULL stream is used if no other stream is specified.
// Default stream has special synchronization properties with other streams.
ihipStream_t *_default_stream;
unsigned _compute_units;
StagingBuffer *_staging_buffer[2]; // one buffer for each direction.
int isLargeBar;
unsigned _device_flags;
// Flags specified when the context is created:
unsigned _ctxFlags;
private:
hipError_t getProperties(hipDeviceProp_t* prop);
const ihipDevice_t *_device;
private: // Critical data, protected with locked access:
// Members of _protected data MUST be accessed through the LockedAccessor.
// Search for LockedAccessor<ihipDeviceCritical_t> for examples; do not access _criticalData directly.
ihipDeviceCritical_t _criticalData;
// Search for LockedAccessor<ihipCtxCritical_t> for examples; do not access _criticalData directly.
ihipCtxCritical_t _criticalData;
};
@@ -633,8 +664,11 @@ extern hsa_agent_t g_cpu_agent ; // the CPU agent.
// Extern functions:
extern void ihipInit();
extern const char *ihipErrorString(hipError_t);
extern ihipCtx_t *ihipGetTlsDefaultCtx();
extern ihipCtx_t *ihipGetDevice(int);
extern ihipCtx_t *ihipGetTlsDefaultCtx();
extern ihipDevice_t *ihipGetDevice(int);
ihipCtx_t * ihipGetPrimaryCtx(unsigned deviceIndex);
extern void ihipSetTs(hipEvent_t e);
template<typename T>
@@ -43,6 +43,7 @@ THE SOFTWARE.
extern "C" {
#endif
typedef struct ihipCtx_t hipCtx_t;
typedef struct ihipStream_t *hipStream_t;
typedef struct hipEvent_t {
struct ihipEvent_t *_handle;
@@ -417,7 +418,6 @@ const char *hipGetErrorString(hipError_t hip_error);
*
* even if the handle goes out-of-scope. To release the memory used by the stream, applicaiton must call hipStreamDestroy.
* Flags controls behavior of the stream. See #hipStreamDefault, #hipStreamNonBlocking.
* @error hipStream_t are under development - with current HIP use the NULL stream.
*/
hipError_t hipStreamCreateWithFlags(hipStream_t *stream, unsigned int flags);
@@ -437,6 +437,8 @@ hipError_t hipStreamCreateWithFlags(hipStream_t *stream, unsigned int flags);
*
* @see hipStreamDestroy
*
* @return
*
*/
hipError_t hipStreamCreate(hipStream_t *stream);