clover: Clean up the event profiling code.
authorFrancisco Jerez <currojerez@riseup.net>
Sun, 6 Oct 2013 20:48:23 +0000 (13:48 -0700)
committerFrancisco Jerez <currojerez@riseup.net>
Mon, 21 Oct 2013 17:47:02 +0000 (10:47 -0700)
Tested-by: Tom Stellard <thomas.stellard@amd.com>
src/gallium/state_trackers/clover/Makefile.sources
src/gallium/state_trackers/clover/api/event.cpp
src/gallium/state_trackers/clover/core/event.cpp
src/gallium/state_trackers/clover/core/event.hpp
src/gallium/state_trackers/clover/core/queue.cpp
src/gallium/state_trackers/clover/core/queue.hpp
src/gallium/state_trackers/clover/core/timestamp.cpp [new file with mode: 0644]
src/gallium/state_trackers/clover/core/timestamp.hpp [new file with mode: 0644]

index e148ec8e584545a29f48dbf75037efcae85b8f97..df1b270fbde4ebec2c1caaae0d118d9140328b55 100644 (file)
@@ -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 \
index ea1576cebd78d4cf22f5affc3a53df9bd33a8a01..849d829f530a207e2aad195d24cc5cc69f9298f5 100644 (file)
@@ -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<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
index cbb97bfe87c26fa777fb344a95cad40a34af922c..b89d2747618db390c7d4a8b0e9656565611d4885 100644 (file)
@@ -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<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
@@ -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<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
@@ -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<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) :
@@ -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)
index de92de079850d0eccd083c463a3886101700b506..ba9d500fbb36a2f625c0a4ea28f6a051d8a4fa4b 100644 (file)
@@ -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<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;
 };
 
@@ -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<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;
    };
 
    ///
@@ -136,8 +137,6 @@ namespace clover {
       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;
index 0b1c494415a660cce395e71f612bcbcb0a15d4d5..d8cf77a43279a0b5f46004e7899f015888016eca 100644 (file)
@@ -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())
index eee852792235ebd198be19455fcadd742fbb9977..4f58968d9e3888dc7cf107a26fb072071b0ae309 100644 (file)
@@ -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 (file)
index 0000000..ab42f24
--- /dev/null
@@ -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 (file)
index 0000000..7fbc6e4
--- /dev/null
@@ -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