core/resource.cpp \
core/sampler.hpp \
core/sampler.cpp \
+ core/timestamp.hpp \
+ core/timestamp.cpp \
core/event.hpp \
core/event.cpp \
core/program.hpp \
PUBLIC cl_int
clGetEventProfilingInfo(cl_event ev, cl_profiling_info param,
- size_t size, void *buf, size_t *size_ret) {
+ size_t size, void *buf, size_t *size_ret) try {
hard_event *hev = dynamic_cast<hard_event *>(ev);
- soft_event *sev = dynamic_cast<soft_event *>(ev);
- if (!hev && !sev)
+ if (!ev)
return CL_INVALID_EVENT;
- if (!hev || !(hev->queue()->props() & CL_QUEUE_PROFILING_ENABLE) ||
- hev->status() != CL_COMPLETE)
+
+ if (!hev || hev->status() != CL_COMPLETE)
return CL_PROFILING_INFO_NOT_AVAILABLE;
switch (param) {
case CL_PROFILING_COMMAND_QUEUED:
- return scalar_property<cl_ulong>(buf, size, size_ret, hev->ts_queued());
+ return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_queued());
case CL_PROFILING_COMMAND_SUBMIT:
- return scalar_property<cl_ulong>(buf, size, size_ret, hev->ts_submit());
+ return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_submit());
case CL_PROFILING_COMMAND_START:
- return scalar_property<cl_ulong>(buf, size, size_ret, hev->ts_start());
+ return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_start());
case CL_PROFILING_COMMAND_END:
- return scalar_property<cl_ulong>(buf, size, size_ret, hev->ts_end());
+ return scalar_property<cl_ulong>(buf, size, size_ret, hev->time_end());
default:
return CL_INVALID_VALUE;
}
+
+} catch (lazy<cl_ulong>::undefined_error &e) {
+ return CL_PROFILING_INFO_NOT_AVAILABLE;
+
+} catch (error &e) {
+ return e.get();
}
PUBLIC cl_int
_cl_event::~_cl_event() {
}
+void
+_cl_event::trigger() {
+ if (!--wait_count) {
+ action_ok(*this);
+
+ while (!__chain.empty()) {
+ __chain.back()->trigger();
+ __chain.pop_back();
+ }
+ }
+}
+
void
_cl_event::abort(cl_int status) {
__status = status;
hard_event::hard_event(clover::command_queue &q, cl_command_type command,
std::vector<clover::event *> deps, action action) :
- _cl_event(q.ctx, deps, action, [](event &ev){}),
- __queue(q), __command(command), __fence(NULL),
- __query_start(NULL), __query_end(NULL) {
- q.sequence(this);
-
- if(q.props() & CL_QUEUE_PROFILING_ENABLE) {
- pipe_screen *screen = q.dev.pipe;
- __ts_queued = screen->get_timestamp(screen);
- }
+ _cl_event(q.ctx, deps, profile(q, action), [](event &ev){}),
+ __queue(q), __command(command), __fence(NULL) {
+ if (q.profiling_enabled())
+ _time_queued = timestamp::current(q);
+ q.sequence(this);
trigger();
}
hard_event::~hard_event() {
pipe_screen *screen = queue()->dev.pipe;
- pipe_context *pipe = queue()->pipe;
screen->fence_reference(screen, &__fence, NULL);
-
- if(__query_start) {
- pipe->destroy_query(pipe, __query_start);
- __query_start = 0;
- }
-
- if(__query_end) {
- pipe->destroy_query(pipe, __query_end);
- __query_end = 0;
- }
-}
-
-void
-hard_event::trigger() {
- if (!--wait_count) {
- /* XXX: Currently, a timestamp query gives wrong results for memory
- * transfers. This is, because we use memcpy instead of the DMA engines. */
-
- if(queue()->props() & CL_QUEUE_PROFILING_ENABLE) {
- pipe_context *pipe = queue()->pipe;
- __query_start = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP);
- pipe->end_query(queue()->pipe, __query_start);
- }
-
- action_ok(*this);
-
- if(queue()->props() & CL_QUEUE_PROFILING_ENABLE) {
- pipe_context *pipe = queue()->pipe;
- pipe_screen *screen = queue()->dev.pipe;
- __query_end = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP);
- pipe->end_query(pipe, __query_end);
- __ts_submit = screen->get_timestamp(screen);
- }
-
- while (!__chain.empty()) {
- __chain.back()->trigger();
- __chain.pop_back();
- }
- }
}
cl_int
throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
}
-cl_ulong
-hard_event::ts_queued() const {
- return __ts_queued;
+const lazy<cl_ulong> &
+hard_event::time_queued() const {
+ return _time_queued;
}
-cl_ulong
-hard_event::ts_submit() const {
- return __ts_submit;
+const lazy<cl_ulong> &
+hard_event::time_submit() const {
+ return _time_submit;
}
-cl_ulong
-hard_event::ts_start() {
- get_query_results();
- return __ts_start;
+const lazy<cl_ulong> &
+hard_event::time_start() const {
+ return _time_start;
}
-cl_ulong
-hard_event::ts_end() {
- get_query_results();
- return __ts_end;
-}
-
-void
-hard_event::get_query_results() {
- pipe_context *pipe = queue()->pipe;
-
- if(__query_start) {
- pipe_query_result result;
- pipe->get_query_result(pipe, __query_start, true, &result);
- __ts_start = result.u64;
- pipe->destroy_query(pipe, __query_start);
- __query_start = 0;
- }
-
- if(__query_end) {
- pipe_query_result result;
- pipe->get_query_result(pipe, __query_end, true, &result);
- __ts_end = result.u64;
- pipe->destroy_query(pipe, __query_end);
- __query_end = 0;
- }
+const lazy<cl_ulong> &
+hard_event::time_end() const {
+ return _time_end;
}
void
screen->fence_reference(screen, &__fence, fence);
}
+event::action
+hard_event::profile(command_queue &q, const action &action) const {
+ if (q.profiling_enabled()) {
+ return [&q, action] (event &ev) {
+ auto &hev = static_cast<hard_event &>(ev);
+
+ hev._time_submit = timestamp::current(q);
+ hev._time_start = timestamp::query(q);
+
+ action(ev);
+
+ hev._time_end = timestamp::query(q);
+ };
+
+ } else {
+ return action;
+ }
+}
+
soft_event::soft_event(clover::context &ctx,
std::vector<clover::event *> deps,
bool __trigger, action action) :
trigger();
}
-void
-soft_event::trigger() {
- if (!--wait_count) {
- action_ok(*this);
-
- while (!__chain.empty()) {
- __chain.back()->trigger();
- __chain.pop_back();
- }
- }
-}
-
cl_int
soft_event::status() const {
if (__status < 0)
#include "core/base.hpp"
#include "core/queue.hpp"
+#include "core/timestamp.hpp"
+#include "util/lazy.hpp"
namespace clover {
typedef struct _cl_event event;
action action_ok, action action_fail);
virtual ~_cl_event();
- virtual void trigger() = 0;
+ void trigger();
void abort(cl_int status);
bool signalled() const;
void chain(clover::event *ev);
cl_int __status;
+ std::vector<clover::ref_ptr<clover::event>> deps;
+
+private:
unsigned wait_count;
action action_ok;
action action_fail;
- std::vector<clover::ref_ptr<clover::event>> deps;
std::vector<clover::ref_ptr<clover::event>> __chain;
};
action action = [](event &){});
~hard_event();
- virtual void trigger();
-
virtual cl_int status() const;
virtual cl_command_queue queue() const;
virtual cl_command_type command() const;
virtual void wait() const;
- cl_ulong ts_queued() const;
- cl_ulong ts_submit() const;
- cl_ulong ts_start();
- cl_ulong ts_end();
- void get_query_results();
+ const lazy<cl_ulong> &time_queued() const;
+ const lazy<cl_ulong> &time_submit() const;
+ const lazy<cl_ulong> &time_start() const;
+ const lazy<cl_ulong> &time_end() const;
friend class ::_cl_command_queue;
private:
virtual void fence(pipe_fence_handle *fence);
+ action profile(command_queue &q, const action &action) const;
clover::command_queue &__queue;
cl_command_type __command;
pipe_fence_handle *__fence;
- cl_ulong __ts_queued, __ts_submit, __ts_start, __ts_end;
- struct pipe_query *__query_start, *__query_end;
+ lazy<cl_ulong> _time_queued, _time_submit, _time_start, _time_end;
};
///
soft_event(clover::context &ctx, std::vector<clover::event *> deps,
bool trigger, action action = [](event &){});
- virtual void trigger();
-
virtual cl_int status() const;
virtual cl_command_queue queue() const;
virtual cl_command_type command() const;
}
}
+cl_command_queue_properties
+_cl_command_queue::props() const {
+ return __props;
+}
+
+bool
+_cl_command_queue::profiling_enabled() const {
+ return __props & CL_QUEUE_PROFILING_ENABLE;
+}
+
void
_cl_command_queue::sequence(clover::hard_event *ev) {
if (!queued_events.empty())
#include "core/base.hpp"
#include "core/context.hpp"
+#include "core/timestamp.hpp"
#include "pipe/p_context.h"
namespace clover {
void flush();
- cl_command_queue_properties props() const {
- return __props;
- }
+ cl_command_queue_properties props() const;
+ bool profiling_enabled() const;
clover::context &ctx;
clover::device &dev;
friend class clover::hard_event;
friend struct _cl_sampler;
friend struct _cl_kernel;
+ friend class clover::timestamp::query;
+ friend class clover::timestamp::current;
private:
/// Serialize a hardware event with respect to the previous ones,
--- /dev/null
+//
+// Copyright 2013 Francisco Jerez
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#include "core/timestamp.hpp"
+#include "core/queue.hpp"
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+
+using namespace clover;
+
+timestamp::query::query(command_queue &q) :
+ q(q),
+ _query(q.pipe->create_query(q.pipe, PIPE_QUERY_TIMESTAMP)) {
+}
+
+timestamp::query::query(query &&other) :
+ q(other.q),
+ _query(other._query) {
+ other._query = NULL;
+}
+
+timestamp::query::~query() {
+ if (_query)
+ q.pipe->destroy_query(q.pipe, _query);
+}
+
+cl_ulong
+timestamp::query::operator()() const {
+ pipe_query_result result;
+
+ if (!q.pipe->get_query_result(q.pipe, _query, false, &result))
+ throw error(CL_PROFILING_INFO_NOT_AVAILABLE);
+
+ return result.u64;
+}
+
+timestamp::current::current(command_queue &q) :
+ result(q.pipe->screen->get_timestamp(q.pipe->screen)) {
+}
+
+cl_ulong
+timestamp::current::operator()() const {
+ return result;
+}
--- /dev/null
+//
+// Copyright 2013 Francisco Jerez
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#ifndef CLOVER_CORE_TIMESTAMP_HPP
+#define CLOVER_CORE_TIMESTAMP_HPP
+
+#include "core/base.hpp"
+
+struct pipe_query;
+
+namespace clover {
+ typedef struct _cl_command_queue command_queue;
+
+ namespace timestamp {
+ ///
+ /// Emit a timestamp query that is executed asynchronously by
+ /// the command queue \a q.
+ ///
+ class query {
+ public:
+ query(command_queue &q);
+ query(query &&other);
+ ~query();
+
+ query &operator=(const query &) = delete;
+
+ ///
+ /// Retrieve the query results.
+ ///
+ cl_ulong operator()() const;
+
+ private:
+ command_queue &q;
+ pipe_query *_query;
+ };
+
+ ///
+ /// Get the current timestamp value.
+ ///
+ class current {
+ public:
+ current(command_queue &q);
+
+ ///
+ /// Retrieve the query results.
+ ///
+ cl_ulong operator()() const;
+
+ private:
+ cl_ulong result;
+ };
+ }
+}
+
+#endif