Home | History | Annotate | Line # | Download | only in core
      1 //
      2 // Copyright 2012 Francisco Jerez
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a
      5 // copy of this software and associated documentation files (the "Software"),
      6 // to deal in the Software without restriction, including without limitation
      7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 // and/or sell copies of the Software, and to permit persons to whom the
      9 // Software is furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 // OTHER DEALINGS IN THE SOFTWARE.
     21 //
     22 
     23 #include "core/queue.hpp"
     24 #include "core/event.hpp"
     25 #include "pipe/p_screen.h"
     26 #include "pipe/p_context.h"
     27 #include "pipe/p_state.h"
     28 
     29 using namespace clover;
     30 
     31 namespace {
     32    void
     33    debug_notify_callback(void *data,
     34                          unsigned *id,
     35                          enum pipe_debug_type type,
     36                          const char *fmt,
     37                          va_list args) {
     38       const command_queue *queue = (const command_queue *)data;
     39       char buffer[1024];
     40       vsnprintf(buffer, sizeof(buffer), fmt, args);
     41       queue->context().notify(buffer);
     42    }
     43 }
     44 
     45 command_queue::command_queue(clover::context &ctx, clover::device &dev,
     46                              cl_command_queue_properties props) :
     47    context(ctx), device(dev), _props(props) {
     48    pipe = dev.pipe->context_create(dev.pipe, NULL, PIPE_CONTEXT_COMPUTE_ONLY);
     49    if (!pipe)
     50       throw error(CL_INVALID_DEVICE);
     51 
     52    if (ctx.notify) {
     53       struct pipe_debug_callback cb;
     54       memset(&cb, 0, sizeof(cb));
     55       cb.debug_message = &debug_notify_callback;
     56       cb.data = this;
     57       if (pipe->set_debug_callback)
     58          pipe->set_debug_callback(pipe, &cb);
     59    }
     60 }
     61 command_queue::command_queue(clover::context &ctx, clover::device &dev,
     62                              std::vector<cl_queue_properties> properties) :
     63    context(ctx), device(dev), _properties(properties), _props(0) {
     64 
     65    for(std::vector<cl_queue_properties>::size_type i = 0; i != properties.size(); i += 2) {
     66       if (properties[i] == 0)
     67          break;
     68       if (properties[i] == CL_QUEUE_PROPERTIES)
     69          _props |= properties[i + 1];
     70       else if (properties[i] != CL_QUEUE_SIZE)
     71          throw error(CL_INVALID_VALUE);
     72    }
     73 
     74    pipe = dev.pipe->context_create(dev.pipe, NULL, PIPE_CONTEXT_COMPUTE_ONLY);
     75    if (!pipe)
     76       throw error(CL_INVALID_DEVICE);
     77 
     78    if (ctx.notify) {
     79       struct pipe_debug_callback cb;
     80       memset(&cb, 0, sizeof(cb));
     81       cb.debug_message = &debug_notify_callback;
     82       cb.data = this;
     83       if (pipe->set_debug_callback)
     84          pipe->set_debug_callback(pipe, &cb);
     85    }
     86 }
     87 
     88 command_queue::~command_queue() {
     89    pipe->destroy(pipe);
     90 }
     91 
     92 void
     93 command_queue::flush() {
     94    std::lock_guard<std::mutex> lock(queued_events_mutex);
     95    flush_unlocked();
     96 }
     97 
     98 void
     99 command_queue::flush_unlocked() {
    100    pipe_screen *screen = device().pipe;
    101    pipe_fence_handle *fence = NULL;
    102 
    103    if (!queued_events.empty()) {
    104       pipe->flush(pipe, &fence, 0);
    105 
    106       while (!queued_events.empty() &&
    107              queued_events.front()().signalled()) {
    108          queued_events.front()().fence(fence);
    109          queued_events.pop_front();
    110       }
    111 
    112       screen->fence_reference(screen, &fence, NULL);
    113    }
    114 }
    115 
    116 void
    117 command_queue::svm_migrate(const std::vector<void const*> &svm_pointers,
    118                            const std::vector<size_t> &sizes,
    119                            cl_mem_migration_flags flags) {
    120    if (!pipe->svm_migrate)
    121       return;
    122 
    123    bool to_device = !(flags & CL_MIGRATE_MEM_OBJECT_HOST);
    124    bool mem_undefined = flags & CL_MIGRATE_MEM_OBJECT_CONTENT_UNDEFINED;
    125    pipe->svm_migrate(pipe, svm_pointers.size(), svm_pointers.data(),
    126                      sizes.data(), to_device, mem_undefined);
    127 }
    128 
    129 cl_command_queue_properties
    130 command_queue::props() const {
    131    return _props;
    132 }
    133 
    134 std::vector<cl_queue_properties>
    135 command_queue::properties() const {
    136    return _properties;
    137 }
    138 
    139 bool
    140 command_queue::profiling_enabled() const {
    141    return _props & CL_QUEUE_PROFILING_ENABLE;
    142 }
    143 
    144 void
    145 command_queue::sequence(hard_event &ev) {
    146    std::lock_guard<std::mutex> lock(queued_events_mutex);
    147    if (!queued_events.empty())
    148       queued_events.back()().chain(ev);
    149 
    150    queued_events.push_back(ev);
    151 
    152    // Arbitrary threshold.
    153    // The CTS tends to run a lot of subtests without flushing with the image
    154    // tests, so flush regularly to prevent stack overflows.
    155    if (queued_events.size() > 1000)
    156       flush_unlocked();
    157 }
    158