2017-12-21 07:45:38 +08:00
|
|
|
/*
|
2019-01-21 18:44:56 +08:00
|
|
|
* Copyright (C) 2017-2019 Intel Corporation
|
2017-12-21 07:45:38 +08:00
|
|
|
*
|
2018-09-19 03:29:07 +08:00
|
|
|
* SPDX-License-Identifier: MIT
|
2017-12-21 07:45:38 +08:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
#include "runtime/api/cl_types.h"
|
|
|
|
#include "runtime/helpers/base_object.h"
|
|
|
|
#include <cstdint>
|
|
|
|
#include <atomic>
|
|
|
|
#include <vector>
|
|
|
|
#include "runtime/helpers/task_information.h"
|
|
|
|
#include "runtime/utilities/idlist.h"
|
|
|
|
#include "runtime/utilities/iflist.h"
|
|
|
|
#include "runtime/event/hw_timestamps.h"
|
|
|
|
#include "runtime/os_interface/os_time.h"
|
|
|
|
#include "runtime/os_interface/performance_counters.h"
|
|
|
|
#include "runtime/helpers/flush_stamp.h"
|
|
|
|
#include "runtime/utilities/arrayref.h"
|
|
|
|
|
|
|
|
#define OCLRT_NUM_TIMESTAMP_BITS (32)
|
|
|
|
|
|
|
|
namespace OCLRT {
|
|
|
|
template <typename TagType>
|
|
|
|
struct TagNode;
|
|
|
|
class CommandQueue;
|
|
|
|
class Context;
|
|
|
|
class Device;
|
2018-10-03 05:37:30 +08:00
|
|
|
class TimestampPacketContainer;
|
2017-12-21 07:45:38 +08:00
|
|
|
|
|
|
|
template <>
|
|
|
|
struct OpenCLObjectMapper<_cl_event> {
|
|
|
|
typedef class Event DerivedType;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Event : public BaseObject<_cl_event>, public IDNode<Event> {
|
|
|
|
public:
|
|
|
|
enum class ECallbackTarget : uint32_t {
|
|
|
|
Queued = 0,
|
|
|
|
Submitted,
|
|
|
|
Running,
|
|
|
|
Completed,
|
|
|
|
MAX,
|
|
|
|
Invalid
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Callback : public IFNode<Callback> {
|
|
|
|
typedef void(CL_CALLBACK *ClbFuncT)(cl_event, cl_int, void *);
|
|
|
|
|
|
|
|
Callback(cl_event event, ClbFuncT clb, cl_int type, void *data)
|
|
|
|
: event(event), callbackFunction(clb), callbackExecutionStatusTarget(type), userData(data) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void execute() {
|
|
|
|
callbackFunction(event, callbackExecutionStatusTarget, userData);
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t getCallbackExecutionStatusTarget() const {
|
|
|
|
return callbackExecutionStatusTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
// From OCL spec :
|
|
|
|
// "If the callback is called as the result of the command associated with
|
|
|
|
// event being abnormally terminated, an appropriate error code for the error that caused
|
|
|
|
// the termination will be passed to event_command_exec_status instead."
|
|
|
|
// This function allows to override this value
|
|
|
|
void overrideCallbackExecutionStatusTarget(int32_t newCallbackExecutionStatusTarget) {
|
|
|
|
DEBUG_BREAK_IF(newCallbackExecutionStatusTarget >= 0);
|
|
|
|
callbackExecutionStatusTarget = newCallbackExecutionStatusTarget;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
cl_event event;
|
|
|
|
ClbFuncT callbackFunction;
|
|
|
|
int32_t callbackExecutionStatusTarget; // minimum event execution status that will triger this callback
|
|
|
|
void *userData;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const cl_ulong objectMagic = 0x80134213A43C981ALL;
|
|
|
|
static const cl_uint eventNotReady;
|
|
|
|
|
|
|
|
Event(CommandQueue *cmdQueue, cl_command_type cmdType,
|
|
|
|
uint32_t taskLevel, uint32_t taskCount);
|
|
|
|
|
|
|
|
Event(const Event &) = delete;
|
|
|
|
Event &operator=(const Event &) = delete;
|
|
|
|
|
|
|
|
~Event() override;
|
|
|
|
|
|
|
|
uint32_t getCompletionStamp(void) const;
|
|
|
|
void updateCompletionStamp(uint32_t taskCount, uint32_t tasklevel, FlushStamp flushStamp);
|
|
|
|
cl_ulong getDelta(cl_ulong startTime,
|
|
|
|
cl_ulong endTime);
|
2017-12-22 18:44:41 +08:00
|
|
|
void setCPUProfilingPath(bool isCPUPath) { this->profilingCpuPath = isCPUPath; }
|
2018-11-27 20:07:41 +08:00
|
|
|
bool isCPUProfilingPath() const {
|
2017-12-21 07:45:38 +08:00
|
|
|
return profilingCpuPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl_int getEventProfilingInfo(cl_profiling_info paramName,
|
|
|
|
size_t paramValueSize,
|
|
|
|
void *paramValue,
|
|
|
|
size_t *paramValueSizeRet);
|
|
|
|
|
2018-11-27 20:07:41 +08:00
|
|
|
bool isProfilingEnabled() const { return profilingEnabled; }
|
2017-12-21 07:45:38 +08:00
|
|
|
|
2017-12-22 18:44:41 +08:00
|
|
|
void setProfilingEnabled(bool profilingEnabled) { this->profilingEnabled = profilingEnabled; }
|
2017-12-21 07:45:38 +08:00
|
|
|
|
2018-11-15 21:47:52 +08:00
|
|
|
TagNode<HwTimeStamps> *getHwTimeStampNode();
|
2017-12-21 07:45:38 +08:00
|
|
|
|
2018-11-27 20:07:41 +08:00
|
|
|
void addTimestampPacketNodes(const TimestampPacketContainer &inputTimestampPacketContainer);
|
2018-10-03 05:37:30 +08:00
|
|
|
TimestampPacketContainer *getTimestampPacketNodes() const;
|
2018-08-28 20:11:25 +08:00
|
|
|
|
2018-11-27 20:07:41 +08:00
|
|
|
bool isPerfCountersEnabled() const {
|
2017-12-21 07:45:38 +08:00
|
|
|
return perfCountersEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setPerfCountersEnabled(bool perfCountersEnabled) {
|
|
|
|
this->perfCountersEnabled = perfCountersEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void copyPerfCounters(InstrPmRegsCfg *config);
|
|
|
|
|
2018-11-15 21:47:52 +08:00
|
|
|
TagNode<HwPerfCounter> *getHwPerfCounterNode();
|
2017-12-21 07:45:38 +08:00
|
|
|
|
|
|
|
std::unique_ptr<FlushStampTracker> flushStamp;
|
|
|
|
std::atomic<uint32_t> taskLevel;
|
|
|
|
|
|
|
|
void addChild(Event &e);
|
|
|
|
|
|
|
|
virtual bool setStatus(cl_int status);
|
|
|
|
|
|
|
|
static cl_int waitForEvents(cl_uint numEvents,
|
|
|
|
const cl_event *eventList);
|
|
|
|
|
2017-12-22 23:05:10 +08:00
|
|
|
void setCommand(std::unique_ptr<Command> newCmd) {
|
2017-12-22 18:44:41 +08:00
|
|
|
UNRECOVERABLE_IF(cmdToSubmit.load());
|
|
|
|
cmdToSubmit.exchange(newCmd.release());
|
2017-12-21 07:45:38 +08:00
|
|
|
eventWithoutCommand = false;
|
|
|
|
}
|
|
|
|
Command *peekCommand() {
|
|
|
|
return cmdToSubmit;
|
|
|
|
}
|
|
|
|
|
|
|
|
IFNodeRef<Event> *peekChildEvents() {
|
|
|
|
return childEventsToNotify.peekHead();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool peekHasChildEvents() {
|
|
|
|
return (peekChildEvents() != nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool peekHasCallbacks(ECallbackTarget target) {
|
|
|
|
if (target >= ECallbackTarget::MAX) {
|
|
|
|
DEBUG_BREAK_IF(true);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (callbacks[(uint32_t)target].peekHead() != nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool peekHasCallbacks() {
|
|
|
|
for (uint32_t i = 0; i < (uint32_t)ECallbackTarget::MAX; ++i) {
|
|
|
|
if (peekHasCallbacks((ECallbackTarget)i)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return the number of events that are blocking this event
|
|
|
|
uint32_t peekNumEventsBlockingThis() const {
|
|
|
|
return parentCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns true if event is completed (in terms of definition provided by OCL spec)
|
2017-12-22 18:44:41 +08:00
|
|
|
// Note from OLC spec :
|
|
|
|
// "A command is considered complete if its execution status
|
|
|
|
// is CL_COMPLETE or a negative value."
|
|
|
|
|
|
|
|
bool isStatusCompleted(const int32_t *executionStatusSnapshot) {
|
|
|
|
return (*executionStatusSnapshot == CL_COMPLETE) || (*executionStatusSnapshot < 0);
|
2017-12-21 07:45:38 +08:00
|
|
|
}
|
|
|
|
|
2017-12-22 18:44:41 +08:00
|
|
|
bool updateStatusAndCheckCompletion();
|
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
// Note from OCL spec :
|
|
|
|
// "A negative integer value causes all enqueued commands that wait on this user event
|
|
|
|
// to be terminated."
|
2019-02-06 15:49:35 +08:00
|
|
|
bool isStatusCompletedByTermination(const int32_t *executionStatusSnapshot = nullptr) const {
|
2017-12-21 07:45:38 +08:00
|
|
|
if (executionStatusSnapshot == nullptr) {
|
|
|
|
return (peekExecutionStatus() < 0);
|
|
|
|
} else {
|
|
|
|
return (*executionStatusSnapshot < 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-06 15:49:35 +08:00
|
|
|
bool peekIsSubmitted(const int32_t *executionStatusSnapshot = nullptr) const {
|
2017-12-21 07:45:38 +08:00
|
|
|
if (executionStatusSnapshot == nullptr) {
|
|
|
|
return (peekExecutionStatus() == CL_SUBMITTED);
|
|
|
|
} else {
|
|
|
|
return (*executionStatusSnapshot == CL_SUBMITTED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-04 20:08:47 +08:00
|
|
|
bool peekIsCmdSubmitted() {
|
|
|
|
return submittedCmd != nullptr;
|
|
|
|
}
|
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
//commands blocked by user event depencies
|
|
|
|
bool isReadyForSubmission();
|
|
|
|
|
|
|
|
// adds a callback (execution state change listener) to this event's list of callbacks
|
|
|
|
void addCallback(Callback::ClbFuncT fn, cl_int type, void *data);
|
|
|
|
|
|
|
|
//returns true on success
|
|
|
|
//if(blocking==false), will return with false instead of blocking while waiting for completion
|
2018-03-21 17:00:49 +08:00
|
|
|
virtual bool wait(bool blocking, bool useQuickKmdSleep);
|
2017-12-21 07:45:38 +08:00
|
|
|
|
|
|
|
bool isUserEvent() const {
|
|
|
|
return (CL_COMMAND_USER == cmdType);
|
|
|
|
}
|
|
|
|
|
2019-02-06 15:49:35 +08:00
|
|
|
bool isEventWithoutCommand() const {
|
2019-02-04 20:08:47 +08:00
|
|
|
return eventWithoutCommand;
|
|
|
|
}
|
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
Context *getContext() {
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandQueue *getCommandQueue() {
|
|
|
|
return cmdQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl_command_type getCommandType() {
|
|
|
|
return cmdType;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual uint32_t getTaskLevel();
|
|
|
|
|
2019-02-06 15:49:35 +08:00
|
|
|
cl_int peekExecutionStatus() const {
|
2017-12-21 07:45:38 +08:00
|
|
|
return executionStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl_int updateEventAndReturnCurrentStatus() {
|
|
|
|
updateExecutionStatus();
|
|
|
|
return executionStatus;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool peekIsBlocked() const {
|
|
|
|
return (peekNumEventsBlockingThis() > 0);
|
|
|
|
}
|
|
|
|
|
2018-03-23 22:55:13 +08:00
|
|
|
virtual void unblockEventBy(Event &event, uint32_t taskLevel, int32_t transitionStatus);
|
2017-12-21 07:45:38 +08:00
|
|
|
|
|
|
|
void updateTaskCount(uint32_t taskCount) {
|
|
|
|
if (taskCount == Event::eventNotReady) {
|
|
|
|
DEBUG_BREAK_IF(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t prevTaskCount = this->taskCount.exchange(taskCount);
|
|
|
|
if ((prevTaskCount != Event::eventNotReady) && (prevTaskCount > taskCount)) {
|
|
|
|
this->taskCount = prevTaskCount;
|
|
|
|
DEBUG_BREAK_IF(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isCurrentCmdQVirtualEvent() {
|
|
|
|
return currentCmdQVirtualEvent;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentCmdQVirtualEvent(bool isCurrentVirtualEvent) {
|
|
|
|
currentCmdQVirtualEvent = isCurrentVirtualEvent;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void updateExecutionStatus();
|
|
|
|
void tryFlushEvent();
|
|
|
|
|
|
|
|
uint32_t peekTaskCount() const {
|
|
|
|
return this->taskCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setQueueTimeStamp(TimeStampData *queueTimeStamp) {
|
|
|
|
this->queueTimeStamp = *queueTimeStamp;
|
|
|
|
};
|
|
|
|
|
|
|
|
void setSubmitTimeStamp(TimeStampData *submitTimeStamp) {
|
|
|
|
this->submitTimeStamp = *submitTimeStamp;
|
|
|
|
};
|
|
|
|
|
|
|
|
void setQueueTimeStamp();
|
|
|
|
void setSubmitTimeStamp();
|
|
|
|
|
|
|
|
void setStartTimeStamp();
|
|
|
|
void setEndTimeStamp();
|
|
|
|
|
|
|
|
void setCmdType(uint32_t cmdType) {
|
|
|
|
this->cmdType = cmdType;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<Event *> &getParentEvents() { return this->parentEvents; }
|
|
|
|
|
2018-02-19 20:30:56 +08:00
|
|
|
virtual bool isExternallySynchronized() const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-02-21 07:15:42 +08:00
|
|
|
static bool checkUserEventDependencies(cl_uint numEventsInWaitList, const cl_event *eventWaitList);
|
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
protected:
|
|
|
|
Event(Context *ctx, CommandQueue *cmdQueue, cl_command_type cmdType,
|
|
|
|
uint32_t taskLevel, uint32_t taskCount);
|
|
|
|
|
|
|
|
ECallbackTarget translateToCallbackTarget(cl_int execStatus) {
|
|
|
|
switch (execStatus) {
|
|
|
|
default: {
|
|
|
|
DEBUG_BREAK_IF(true);
|
|
|
|
return ECallbackTarget::Invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
case CL_QUEUED:
|
|
|
|
return ECallbackTarget::Queued;
|
|
|
|
case CL_SUBMITTED:
|
|
|
|
return ECallbackTarget::Submitted;
|
|
|
|
case CL_RUNNING:
|
|
|
|
return ECallbackTarget::Running;
|
|
|
|
case CL_COMPLETE:
|
|
|
|
return ECallbackTarget::Completed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-21 18:44:56 +08:00
|
|
|
bool calcProfilingData();
|
2019-01-31 20:32:02 +08:00
|
|
|
MOCKABLE_VIRTUAL void calculateProfilingDataInternal(uint64_t contextStartTS, uint64_t contextEndTS, uint64_t *contextCompleteTS, uint64_t globalStartTS);
|
2019-01-21 18:44:56 +08:00
|
|
|
|
2017-12-21 07:45:38 +08:00
|
|
|
// executes all callbacks associated with this event
|
|
|
|
void executeCallbacks(int32_t executionStatus);
|
|
|
|
|
|
|
|
// transitions event to new execution state
|
|
|
|
// guarantees that newStatus <= oldStatus
|
2018-05-29 19:30:39 +08:00
|
|
|
void transitionExecutionStatus(int32_t newExecutionStatus) const;
|
2017-12-21 07:45:38 +08:00
|
|
|
|
|
|
|
//vector storing events that needs to be notified when this event is ready to go
|
|
|
|
IFRefList<Event, true, true> childEventsToNotify;
|
|
|
|
void unblockEventsBlockedByThis(int32_t transitionStatus);
|
|
|
|
void submitCommand(bool abortBlockedTasks);
|
|
|
|
|
|
|
|
bool currentCmdQVirtualEvent;
|
|
|
|
std::atomic<Command *> cmdToSubmit;
|
|
|
|
std::atomic<Command *> submittedCmd;
|
|
|
|
bool eventWithoutCommand = true;
|
|
|
|
|
|
|
|
Context *ctx;
|
|
|
|
CommandQueue *cmdQueue;
|
|
|
|
cl_command_type cmdType;
|
|
|
|
|
|
|
|
// callbacks to be executed when this event changes its execution state
|
|
|
|
IFList<Callback, true, true> callbacks[(uint32_t)ECallbackTarget::MAX];
|
|
|
|
|
|
|
|
// can be accessed only with transitionExecutionState
|
|
|
|
// this is to ensure state consitency event when doning lock-free multithreading
|
|
|
|
// e.g. CL_COMPLETE -> CL_SUBMITTED or CL_SUBMITTED -> CL_QUEUED becomes forbiden
|
|
|
|
mutable std::atomic<int32_t> executionStatus;
|
|
|
|
// Timestamps
|
2017-12-22 18:44:41 +08:00
|
|
|
bool profilingEnabled;
|
|
|
|
bool profilingCpuPath;
|
2017-12-21 07:45:38 +08:00
|
|
|
bool dataCalculated;
|
|
|
|
TimeStampData queueTimeStamp;
|
|
|
|
TimeStampData submitTimeStamp;
|
|
|
|
uint64_t startTimeStamp;
|
|
|
|
uint64_t endTimeStamp;
|
|
|
|
uint64_t completeTimeStamp;
|
|
|
|
bool perfCountersEnabled;
|
2018-08-28 20:11:25 +08:00
|
|
|
TagNode<HwTimeStamps> *timeStampNode = nullptr;
|
|
|
|
TagNode<HwPerfCounter> *perfCounterNode = nullptr;
|
2018-10-03 05:37:30 +08:00
|
|
|
std::unique_ptr<TimestampPacketContainer> timestampPacketContainer;
|
2018-08-28 20:11:25 +08:00
|
|
|
InstrPmRegsCfg *perfConfigurationData = nullptr;
|
2017-12-21 07:45:38 +08:00
|
|
|
//number of events this event depends on
|
|
|
|
std::atomic<int> parentCount;
|
|
|
|
//event parents
|
|
|
|
std::vector<Event *> parentEvents;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// can be accessed only with updateTaskCount
|
|
|
|
std::atomic<uint32_t> taskCount;
|
|
|
|
};
|
|
|
|
} // namespace OCLRT
|