From ebfdce079b8f99f92dff4d58a53c27e0888c373f Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Sun, 6 Oct 2013 13:48:23 -0700 Subject: [PATCH] clover: Clean up the event profiling code. Tested-by: Tom Stellard --- .../state_trackers/clover/Makefile.sources | 2 + .../state_trackers/clover/api/event.cpp | 23 +-- .../state_trackers/clover/core/event.cpp | 144 ++++++------------ .../state_trackers/clover/core/event.hpp | 25 ++- .../state_trackers/clover/core/queue.cpp | 10 ++ .../state_trackers/clover/core/queue.hpp | 8 +- .../state_trackers/clover/core/timestamp.cpp | 63 ++++++++ .../state_trackers/clover/core/timestamp.hpp | 74 +++++++++ 8 files changed, 228 insertions(+), 121 deletions(-) create mode 100644 src/gallium/state_trackers/clover/core/timestamp.cpp create mode 100644 src/gallium/state_trackers/clover/core/timestamp.hpp diff --git a/src/gallium/state_trackers/clover/Makefile.sources b/src/gallium/state_trackers/clover/Makefile.sources index e148ec8e584..df1b270fbde 100644 --- a/src/gallium/state_trackers/clover/Makefile.sources +++ b/src/gallium/state_trackers/clover/Makefile.sources @@ -29,6 +29,8 @@ CPP_SOURCES := \ core/resource.cpp \ core/sampler.hpp \ core/sampler.cpp \ + core/timestamp.hpp \ + core/timestamp.cpp \ core/event.hpp \ core/event.cpp \ core/program.hpp \ diff --git a/src/gallium/state_trackers/clover/api/event.cpp b/src/gallium/state_trackers/clover/api/event.cpp index ea1576cebd7..849d829f530 100644 --- a/src/gallium/state_trackers/clover/api/event.cpp +++ b/src/gallium/state_trackers/clover/api/event.cpp @@ -216,32 +216,37 @@ clEnqueueWaitForEvents(cl_command_queue q, cl_uint num_evs, 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(ev); - soft_event *sev = dynamic_cast(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(buf, size, size_ret, hev->ts_queued()); + return scalar_property(buf, size, size_ret, hev->time_queued()); case CL_PROFILING_COMMAND_SUBMIT: - return scalar_property(buf, size, size_ret, hev->ts_submit()); + return scalar_property(buf, size, size_ret, hev->time_submit()); case CL_PROFILING_COMMAND_START: - return scalar_property(buf, size, size_ret, hev->ts_start()); + return scalar_property(buf, size, size_ret, hev->time_start()); case CL_PROFILING_COMMAND_END: - return scalar_property(buf, size, size_ret, hev->ts_end()); + return scalar_property(buf, size, size_ret, hev->time_end()); default: return CL_INVALID_VALUE; } + +} catch (lazy::undefined_error &e) { + return CL_PROFILING_INFO_NOT_AVAILABLE; + +} catch (error &e) { + return e.get(); } PUBLIC cl_int diff --git a/src/gallium/state_trackers/clover/core/event.cpp b/src/gallium/state_trackers/clover/core/event.cpp index cbb97bfe87c..b89d2747618 100644 --- a/src/gallium/state_trackers/clover/core/event.cpp +++ b/src/gallium/state_trackers/clover/core/event.cpp @@ -37,6 +37,18 @@ _cl_event::_cl_event(clover::context &ctx, _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; @@ -64,62 +76,18 @@ _cl_event::chain(clover::event *ev) { hard_event::hard_event(clover::command_queue &q, cl_command_type command, std::vector 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 @@ -161,47 +129,24 @@ hard_event::wait() const { throw error(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST); } -cl_ulong -hard_event::ts_queued() const { - return __ts_queued; +const lazy & +hard_event::time_queued() const { + return _time_queued; } -cl_ulong -hard_event::ts_submit() const { - return __ts_submit; +const lazy & +hard_event::time_submit() const { + return _time_submit; } -cl_ulong -hard_event::ts_start() { - get_query_results(); - return __ts_start; +const lazy & +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 & +hard_event::time_end() const { + return _time_end; } void @@ -210,6 +155,25 @@ hard_event::fence(pipe_fence_handle *fence) { 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(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 deps, bool __trigger, action action) : @@ -218,18 +182,6 @@ soft_event::soft_event(clover::context &ctx, 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) diff --git a/src/gallium/state_trackers/clover/core/event.hpp b/src/gallium/state_trackers/clover/core/event.hpp index de92de07985..ba9d500fbb3 100644 --- a/src/gallium/state_trackers/clover/core/event.hpp +++ b/src/gallium/state_trackers/clover/core/event.hpp @@ -27,6 +27,8 @@ #include "core/base.hpp" #include "core/queue.hpp" +#include "core/timestamp.hpp" +#include "util/lazy.hpp" namespace clover { typedef struct _cl_event event; @@ -57,7 +59,7 @@ public: action action_ok, action action_fail); virtual ~_cl_event(); - virtual void trigger() = 0; + void trigger(); void abort(cl_int status); bool signalled() const; @@ -72,10 +74,12 @@ protected: void chain(clover::event *ev); cl_int __status; + std::vector> deps; + +private: unsigned wait_count; action action_ok; action action_fail; - std::vector> deps; std::vector> __chain; }; @@ -99,29 +103,26 @@ namespace clover { 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 &time_queued() const; + const lazy &time_submit() const; + const lazy &time_start() const; + const lazy &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 _time_queued, _time_submit, _time_start, _time_end; }; /// @@ -136,8 +137,6 @@ namespace clover { soft_event(clover::context &ctx, std::vector 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; diff --git a/src/gallium/state_trackers/clover/core/queue.cpp b/src/gallium/state_trackers/clover/core/queue.cpp index 0b1c494415a..d8cf77a4327 100644 --- a/src/gallium/state_trackers/clover/core/queue.cpp +++ b/src/gallium/state_trackers/clover/core/queue.cpp @@ -60,6 +60,16 @@ _cl_command_queue::flush() { } } +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()) diff --git a/src/gallium/state_trackers/clover/core/queue.hpp b/src/gallium/state_trackers/clover/core/queue.hpp index eee85279223..4f58968d9e3 100644 --- a/src/gallium/state_trackers/clover/core/queue.hpp +++ b/src/gallium/state_trackers/clover/core/queue.hpp @@ -25,6 +25,7 @@ #include "core/base.hpp" #include "core/context.hpp" +#include "core/timestamp.hpp" #include "pipe/p_context.h" namespace clover { @@ -43,9 +44,8 @@ public: 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; @@ -56,6 +56,8 @@ public: 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, diff --git a/src/gallium/state_trackers/clover/core/timestamp.cpp b/src/gallium/state_trackers/clover/core/timestamp.cpp new file mode 100644 index 00000000000..ab42f2414bb --- /dev/null +++ b/src/gallium/state_trackers/clover/core/timestamp.cpp @@ -0,0 +1,63 @@ +// +// 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; +} diff --git a/src/gallium/state_trackers/clover/core/timestamp.hpp b/src/gallium/state_trackers/clover/core/timestamp.hpp new file mode 100644 index 00000000000..7fbc6e4c27c --- /dev/null +++ b/src/gallium/state_trackers/clover/core/timestamp.hpp @@ -0,0 +1,74 @@ +// +// 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 -- 2.30.2