Clover Git
OpenCL 1.1 software implementation

commandqueue.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Denis Steckelmacher <steckdenis@yahoo.fr>
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *     * Redistributions of source code must retain the above copyright
00008  *       notice, this list of conditions and the following disclaimer.
00009  *     * Redistributions in binary form must reproduce the above copyright
00010  *       notice, this list of conditions and the following disclaimer in the
00011  *       documentation and/or other materials provided with the distribution.
00012  *     * Neither the name of the copyright holder nor the
00013  *       names of its contributors may be used to endorse or promote products
00014  *       derived from this software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00020  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00033 #include "commandqueue.h"
00034 #include "context.h"
00035 #include "deviceinterface.h"
00036 #include "propertylist.h"
00037 #include "events.h"
00038 
00039 #include <cstring>
00040 #include <cstdlib>
00041 #include <ctime>
00042 #include <iostream>
00043 
00044 using namespace Coal;
00045 
00046 /*
00047  * CommandQueue
00048  */
00049 
00050 CommandQueue::CommandQueue(Context *ctx,
00051                            DeviceInterface *device,
00052                            cl_command_queue_properties properties,
00053                            cl_int *errcode_ret)
00054 : Object(Object::T_CommandQueue, ctx), p_device(device),
00055   p_properties(properties), p_flushed(true)
00056 {
00057     // Initialize the locking machinery
00058     pthread_mutex_init(&p_event_list_mutex, 0);
00059     pthread_cond_init(&p_event_list_cond, 0);
00060 
00061     // Check that the device belongs to the context
00062     if (!ctx->hasDevice(device))
00063     {
00064         *errcode_ret = CL_INVALID_DEVICE;
00065         return;
00066     }
00067 
00068     *errcode_ret = checkProperties();
00069 }
00070 
00071 CommandQueue::~CommandQueue()
00072 {
00073     // Free the mutex
00074     pthread_mutex_destroy(&p_event_list_mutex);
00075     pthread_cond_destroy(&p_event_list_cond);
00076 }
00077 
00078 cl_int CommandQueue::info(cl_command_queue_info param_name,
00079                           size_t param_value_size,
00080                           void *param_value,
00081                           size_t *param_value_size_ret) const
00082 {
00083     void *value = 0;
00084     size_t value_length = 0;
00085 
00086     union {
00087         cl_uint cl_uint_var;
00088         cl_device_id cl_device_id_var;
00089         cl_context cl_context_var;
00090         cl_command_queue_properties cl_command_queue_properties_var;
00091     };
00092 
00093     switch (param_name)
00094     {
00095         case CL_QUEUE_CONTEXT:
00096             SIMPLE_ASSIGN(cl_context, parent());
00097             break;
00098 
00099         case CL_QUEUE_DEVICE:
00100             SIMPLE_ASSIGN(cl_device_id, p_device);
00101             break;
00102 
00103         case CL_QUEUE_REFERENCE_COUNT:
00104             SIMPLE_ASSIGN(cl_uint, references());
00105             break;
00106 
00107         case CL_QUEUE_PROPERTIES:
00108             SIMPLE_ASSIGN(cl_command_queue_properties, p_properties);
00109             break;
00110 
00111         default:
00112             return CL_INVALID_VALUE;
00113     }
00114 
00115     if (param_value && param_value_size < value_length)
00116         return CL_INVALID_VALUE;
00117 
00118     if (param_value_size_ret)
00119         *param_value_size_ret = value_length;
00120 
00121     if (param_value)
00122         std::memcpy(param_value, value, value_length);
00123 
00124     return CL_SUCCESS;
00125 }
00126 
00127 cl_int CommandQueue::setProperty(cl_command_queue_properties properties,
00128                                  cl_bool enable,
00129                                  cl_command_queue_properties *old_properties)
00130 {
00131     if (old_properties)
00132         *old_properties = p_properties;
00133 
00134     if (enable)
00135         p_properties |= properties;
00136     else
00137         p_properties &= ~properties;
00138 
00139     return checkProperties();
00140 }
00141 
00142 cl_int CommandQueue::checkProperties() const
00143 {
00144     // Check that all the properties are valid
00145     cl_command_queue_properties properties =
00146         CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE |
00147         CL_QUEUE_PROFILING_ENABLE;
00148 
00149     if ((p_properties & properties) != p_properties)
00150         return CL_INVALID_VALUE;
00151 
00152     // Check that the device handles these properties
00153     cl_int result;
00154 
00155     result = p_device->info(CL_DEVICE_QUEUE_PROPERTIES,
00156                             sizeof(cl_command_queue_properties),
00157                             &properties,
00158                             0);
00159 
00160     if (result != CL_SUCCESS)
00161         return result;
00162 
00163     if ((p_properties & properties) != p_properties)
00164         return CL_INVALID_QUEUE_PROPERTIES;
00165 
00166     return CL_SUCCESS;
00167 }
00168 
00169 void CommandQueue::flush()
00170 {
00171     // Wait for the command queue to be in state "flushed".
00172     pthread_mutex_lock(&p_event_list_mutex);
00173 
00174     while (!p_flushed)
00175         pthread_cond_wait(&p_event_list_cond, &p_event_list_mutex);
00176 
00177     pthread_mutex_unlock(&p_event_list_mutex);
00178 }
00179 
00180 void CommandQueue::finish()
00181 {
00182     // As pushEventsOnDevice doesn't remove SUCCESS events, we may need
00183     // to do that here in order not to be stuck.
00184     cleanEvents();
00185 
00186     // All the queued events must have completed. When they are, they get
00187     // deleted from the command queue, so simply wait for it to become empty.
00188     pthread_mutex_lock(&p_event_list_mutex);
00189 
00190     while (p_events.size() != 0)
00191         pthread_cond_wait(&p_event_list_cond, &p_event_list_mutex);
00192 
00193     pthread_mutex_unlock(&p_event_list_mutex);
00194 }
00195 
00196 cl_int CommandQueue::queueEvent(Event *event)
00197 {
00198     // Let the device initialize the event (for instance, a pointer at which
00199     // memory would be mapped)
00200     cl_int rs = p_device->initEventDeviceData(event);
00201 
00202     if (rs != CL_SUCCESS)
00203         return rs;
00204 
00205     // Append the event at the end of the list
00206     pthread_mutex_lock(&p_event_list_mutex);
00207 
00208     p_events.push_back(event);
00209     p_flushed = false;
00210 
00211     pthread_mutex_unlock(&p_event_list_mutex);
00212 
00213     // Timing info if needed
00214     if (p_properties & CL_QUEUE_PROFILING_ENABLE)
00215         event->updateTiming(Event::Queue);
00216 
00217     // Explore the list for events we can push on the device
00218     pushEventsOnDevice();
00219 
00220     return CL_SUCCESS;
00221 }
00222 
00223 void CommandQueue::cleanEvents()
00224 {
00225     pthread_mutex_lock(&p_event_list_mutex);
00226 
00227     std::list<Event *>::iterator it = p_events.begin(), oldit;
00228 
00229     while (it != p_events.end())
00230     {
00231         Event *event = *it;
00232 
00233         if (event->status() == Event::Complete)
00234         {
00235             // We cannot be deleted from inside us
00236             event->setReleaseParent(false);
00237             oldit = it;
00238             ++it;
00239 
00240             p_events.erase(oldit);
00241             clReleaseEvent((cl_event)event);
00242         }
00243         else
00244         {
00245             ++it;
00246         }
00247     }
00248 
00249     // We have cleared the list, so wake up the sleeping threads
00250     if (p_events.size() == 0)
00251         pthread_cond_broadcast(&p_event_list_cond);
00252 
00253     pthread_mutex_unlock(&p_event_list_mutex);
00254 
00255     // Check now if we have to be deleted
00256     if (references() == 0)
00257         delete this;
00258 }
00259 
00260 void CommandQueue::pushEventsOnDevice()
00261 {
00262     pthread_mutex_lock(&p_event_list_mutex);
00263     // Explore the events in p_events and push on the device all of them that
00264     // are :
00265     //
00266     // - Not already pushed (in Event::Queued state)
00267     // - Not after a barrier, except if we begin with a barrier
00268     // - If we are in-order, only the first event in Event::Queued state can
00269     //   be pushed
00270 
00271     std::list<Event *>::iterator it = p_events.begin();
00272     bool first = true;
00273 
00274     // We assume that we will flush the command queue (submit all the events)
00275     // This will be changed in the while() when we know that not all events
00276     // are submitted.
00277     p_flushed = true;
00278 
00279     while (it != p_events.end())
00280     {
00281         Event *event = *it;
00282 
00283         // If the event is completed, remove it
00284         if (event->status() == Event::Complete)
00285         {
00286             ++it;
00287             continue;
00288         }
00289 
00290         // We cannot do out-of-order, so we can only push the first event.
00291         if ((p_properties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE) == 0 &&
00292             !first)
00293         {
00294             p_flushed = false; // There are remaining events.
00295             break;
00296         }
00297 
00298         // Stop if we encounter a barrier that isn't the first event in the list.
00299         if (event->type() == Event::Barrier && !first)
00300         {
00301             // We have events to wait, stop
00302             p_flushed = false;
00303             break;
00304         }
00305 
00306         // Completed events and first barriers are out, it remains real events
00307         // that have to block in-order execution.
00308         first = false;
00309 
00310         // If the event is not "pushable" (in Event::Queued state), skip it
00311         // It is either Submitted or Running.
00312         if (event->status() != Event::Queued)
00313         {
00314             ++it;
00315             continue;
00316         }
00317 
00318         // Check that all the waiting-on events of this event are finished
00319         cl_uint count;
00320         const Event **event_wait_list;
00321         bool skip_event = false;
00322 
00323         event_wait_list = event->waitEvents(count);
00324 
00325         for (cl_uint i=0; i<count; ++i)
00326         {
00327             if (event_wait_list[i]->status() != Event::Complete)
00328             {
00329                 skip_event = true;
00330                 p_flushed = false;
00331                 break;
00332             }
00333         }
00334 
00335         if (skip_event)
00336         {
00337             // If we encounter a WaitForEvents event that is not "finished",
00338             // don't push events after it.
00339             if (event->type() == Event::WaitForEvents)
00340                 break;
00341 
00342             // The event has its dependencies not already met.
00343             ++it;
00344             continue;
00345         }
00346 
00347         // The event can be pushed, if we need to
00348         if (!event->isDummy())
00349         {
00350             if (p_properties & CL_QUEUE_PROFILING_ENABLE)
00351                 event->updateTiming(Event::Submit);
00352 
00353             event->setStatus(Event::Submitted);
00354             p_device->pushEvent(event);
00355         }
00356         else
00357         {
00358             // Set the event as completed. This will call pushEventsOnDevice,
00359             // again, so release the lock to avoid a deadlock. We also return
00360             // because the recursive call will continue our work.
00361             pthread_mutex_unlock(&p_event_list_mutex);
00362             event->setStatus(Event::Complete);
00363             return;
00364         }
00365     }
00366 
00367     if (p_flushed)
00368         pthread_cond_broadcast(&p_event_list_cond);
00369 
00370     pthread_mutex_unlock(&p_event_list_mutex);
00371 }
00372 
00373 Event **CommandQueue::events(unsigned int &count)
00374 {
00375     Event **result;
00376 
00377     pthread_mutex_lock(&p_event_list_mutex);
00378 
00379     count = p_events.size();
00380     result = (Event **)std::malloc(count * sizeof(Event *));
00381 
00382     // Copy each event of the list into result, retaining them
00383     unsigned int index = 0;
00384     std::list<Event *>::iterator it = p_events.begin();
00385 
00386     while (it != p_events.end())
00387     {
00388         result[index] = *it;
00389         result[index]->reference();
00390 
00391         ++it;
00392         ++index;
00393     }
00394 
00395     // Now result contains an immutable list of events. Even if the events
00396     // become completed in another thread while result is used, the events
00397     // are retained and so guaranteed to remain valid.
00398     pthread_mutex_unlock(&p_event_list_mutex);
00399 
00400     return result;
00401 }
00402 
00403 /*
00404  * Event
00405  */
00406 
00407 Event::Event(CommandQueue *parent,
00408              Status status,
00409              cl_uint num_events_in_wait_list,
00410              const Event **event_wait_list,
00411              cl_int *errcode_ret)
00412 : Object(Object::T_Event, parent),
00413   p_num_events_in_wait_list(num_events_in_wait_list), p_event_wait_list(0),
00414   p_status(status), p_device_data(0)
00415 {
00416     // Initialize the locking machinery
00417     pthread_cond_init(&p_state_change_cond, 0);
00418     pthread_mutex_init(&p_state_mutex, 0);
00419 
00420     std::memset(&p_timing, 0, sizeof(p_timing));
00421 
00422     // Check sanity of parameters
00423     if (!event_wait_list && num_events_in_wait_list)
00424     {
00425         *errcode_ret = CL_INVALID_EVENT_WAIT_LIST;
00426         return;
00427     }
00428 
00429     if (event_wait_list && !num_events_in_wait_list)
00430     {
00431         *errcode_ret = CL_INVALID_EVENT_WAIT_LIST;
00432         return;
00433     }
00434 
00435     // Check that none of the events in event_wait_list is in an error state
00436     for (cl_uint i=0; i<num_events_in_wait_list; ++i)
00437     {
00438         if (event_wait_list[i] == 0)
00439         {
00440             *errcode_ret = CL_INVALID_EVENT_WAIT_LIST;
00441             return;
00442         }
00443         else if (event_wait_list[i]->status() < 0)
00444         {
00445             *errcode_ret = CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST;
00446             return;
00447         }
00448     }
00449 
00450     // Allocate a new buffer for the events to wait
00451     if (num_events_in_wait_list)
00452     {
00453         const unsigned int len = num_events_in_wait_list * sizeof(Event *);
00454         p_event_wait_list = (const Event **)std::malloc(len);
00455 
00456         if (!p_event_wait_list)
00457         {
00458             *errcode_ret = CL_OUT_OF_HOST_MEMORY;
00459             return;
00460         }
00461 
00462         std::memcpy((void *)p_event_wait_list, (void *)event_wait_list, len);
00463     }
00464 
00465     // Explore the events we are waiting on and reference them
00466     for (cl_uint i=0; i<num_events_in_wait_list; ++i)
00467     {
00468         clRetainEvent((cl_event)event_wait_list[i]);
00469 
00470         if (event_wait_list[i]->type() == Event::User && parent)
00471             ((UserEvent *)event_wait_list[i])->addDependentCommandQueue(parent);
00472     }
00473 }
00474 
00475 void Event::freeDeviceData()
00476 {
00477     if (parent() && p_device_data)
00478     {
00479         DeviceInterface *device = 0;
00480         ((CommandQueue *)parent())->info(CL_QUEUE_DEVICE, sizeof(DeviceInterface *), &device, 0);
00481 
00482         device->freeEventDeviceData(this);
00483     }
00484 }
00485 
00486 Event::~Event()
00487 {
00488     for (cl_uint i=0; i<p_num_events_in_wait_list; ++i)
00489         clReleaseEvent((cl_event)p_event_wait_list[i]);
00490 
00491     if (p_event_wait_list)
00492         std::free((void *)p_event_wait_list);
00493 
00494     pthread_mutex_destroy(&p_state_mutex);
00495     pthread_cond_destroy(&p_state_change_cond);
00496 }
00497 
00498 bool Event::isDummy() const
00499 {
00500     // A dummy event has nothing to do on an execution device and must be
00501     // completed directly after being "submitted".
00502 
00503     switch (type())
00504     {
00505         case Marker:
00506         case User:
00507         case Barrier:
00508         case WaitForEvents:
00509             return true;
00510 
00511         default:
00512             return false;
00513     }
00514 }
00515 
00516 void Event::setStatus(Status status)
00517 {
00518     // TODO: If status < 0, terminate all the events depending on us.
00519     pthread_mutex_lock(&p_state_mutex);
00520     p_status = status;
00521 
00522     pthread_cond_broadcast(&p_state_change_cond);
00523 
00524     // Call the callbacks
00525     std::multimap<Status, CallbackData>::const_iterator it;
00526     std::pair<std::multimap<Status, CallbackData>::const_iterator,
00527               std::multimap<Status, CallbackData>::const_iterator> ret;
00528 
00529     ret = p_callbacks.equal_range(status > 0 ? status : Complete);
00530 
00531     for (it=ret.first; it!=ret.second; ++it)
00532     {
00533         const CallbackData &data = (*it).second;
00534         data.callback((cl_event)this, p_status, data.user_data);
00535     }
00536 
00537     pthread_mutex_unlock(&p_state_mutex);
00538 
00539     // If the event is completed, inform our parent so it can push other events
00540     // to the device.
00541     if (parent() && status == Complete)
00542         ((CommandQueue *)parent())->pushEventsOnDevice();
00543     else if (type() == Event::User)
00544         ((UserEvent *)this)->flushQueues();
00545 }
00546 
00547 void Event::setDeviceData(void *data)
00548 {
00549     p_device_data = data;
00550 }
00551 
00552 void Event::updateTiming(Timing timing)
00553 {
00554     if (timing >= Max)
00555         return;
00556 
00557     pthread_mutex_lock(&p_state_mutex);
00558 
00559     // Don't update more than one time (NDRangeKernel for example)
00560     if (p_timing[timing])
00561     {
00562         pthread_mutex_unlock(&p_state_mutex);
00563         return;
00564     }
00565 
00566     struct timespec tp;
00567     cl_ulong rs;
00568 
00569     if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
00570         clock_gettime(CLOCK_REALTIME, &tp);
00571 
00572     rs = tp.tv_nsec;
00573     rs += tp.tv_sec * 1000000;
00574 
00575     p_timing[timing] = rs;
00576 
00577     pthread_mutex_unlock(&p_state_mutex);
00578 }
00579 
00580 Event::Status Event::status() const
00581 {
00582     // HACK : We need const qualifier but we also need to lock a mutex
00583     Event *me = (Event *)(void *)this;
00584 
00585     pthread_mutex_lock(&me->p_state_mutex);
00586 
00587     Status ret = p_status;
00588 
00589     pthread_mutex_unlock(&me->p_state_mutex);
00590 
00591     return ret;
00592 }
00593 
00594 void Event::waitForStatus(Status status)
00595 {
00596     pthread_mutex_lock(&p_state_mutex);
00597 
00598     while (p_status != status && p_status > 0)
00599     {
00600         pthread_cond_wait(&p_state_change_cond, &p_state_mutex);
00601     }
00602 
00603     pthread_mutex_unlock(&p_state_mutex);
00604 }
00605 
00606 void *Event::deviceData()
00607 {
00608     return p_device_data;
00609 }
00610 
00611 const Event **Event::waitEvents(cl_uint &count) const
00612 {
00613     count = p_num_events_in_wait_list;
00614     return p_event_wait_list;
00615 }
00616 
00617 void Event::setCallback(cl_int command_exec_callback_type,
00618                         event_callback callback,
00619                         void *user_data)
00620 {
00621     CallbackData data;
00622 
00623     data.callback = callback;
00624     data.user_data = user_data;
00625 
00626     pthread_mutex_lock(&p_state_mutex);
00627 
00628     p_callbacks.insert(std::pair<Status, CallbackData>(
00629         (Status)command_exec_callback_type,
00630         data));
00631 
00632     pthread_mutex_unlock(&p_state_mutex);
00633 }
00634 
00635 cl_int Event::info(cl_event_info param_name,
00636                    size_t param_value_size,
00637                    void *param_value,
00638                    size_t *param_value_size_ret) const
00639 {
00640     void *value = 0;
00641     size_t value_length = 0;
00642 
00643     union {
00644         cl_command_queue cl_command_queue_var;
00645         cl_context cl_context_var;
00646         cl_command_type cl_command_type_var;
00647         cl_int cl_int_var;
00648         cl_uint cl_uint_var;
00649     };
00650 
00651     switch (param_name)
00652     {
00653         case CL_EVENT_COMMAND_QUEUE:
00654             SIMPLE_ASSIGN(cl_command_queue, parent());
00655             break;
00656 
00657         case CL_EVENT_CONTEXT:
00658             if (parent())
00659             {
00660                 SIMPLE_ASSIGN(cl_context, parent()->parent());
00661             }
00662             else
00663             {
00664                 if (type() == User)
00665                     SIMPLE_ASSIGN(cl_context, ((UserEvent *)this)->context())
00666                 else
00667                     SIMPLE_ASSIGN(cl_context, 0);
00668             }
00669 
00670         case CL_EVENT_COMMAND_TYPE:
00671             SIMPLE_ASSIGN(cl_command_type, type());
00672             break;
00673 
00674         case CL_EVENT_COMMAND_EXECUTION_STATUS:
00675             SIMPLE_ASSIGN(cl_int, status());
00676             break;
00677 
00678         case CL_EVENT_REFERENCE_COUNT:
00679             SIMPLE_ASSIGN(cl_uint, references());
00680             break;
00681 
00682         default:
00683             return CL_INVALID_VALUE;
00684     }
00685 
00686     if (param_value && param_value_size < value_length)
00687         return CL_INVALID_VALUE;
00688 
00689     if (param_value_size_ret)
00690         *param_value_size_ret = value_length;
00691 
00692     if (param_value)
00693         std::memcpy(param_value, value, value_length);
00694 
00695     return CL_SUCCESS;
00696 }
00697 
00698 cl_int Event::profilingInfo(cl_profiling_info param_name,
00699                             size_t param_value_size,
00700                             void *param_value,
00701                             size_t *param_value_size_ret) const
00702 {
00703     if (type() == Event::User)
00704         return CL_PROFILING_INFO_NOT_AVAILABLE;
00705 
00706     // Check that the Command Queue has profiling enabled
00707     cl_command_queue_properties queue_props;
00708     cl_int rs;
00709 
00710     rs = ((CommandQueue *)parent())->info(CL_QUEUE_PROPERTIES,
00711                                           sizeof(cl_command_queue_properties),
00712                                           &queue_props, 0);
00713 
00714     if (rs != CL_SUCCESS)
00715         return rs;
00716 
00717     if ((queue_props & CL_QUEUE_PROFILING_ENABLE) == 0)
00718         return CL_PROFILING_INFO_NOT_AVAILABLE;
00719 
00720     if (status() != Event::Complete)
00721         return CL_PROFILING_INFO_NOT_AVAILABLE;
00722 
00723     void *value = 0;
00724     size_t value_length = 0;
00725     cl_ulong cl_ulong_var;
00726 
00727     switch (param_name)
00728     {
00729         case CL_PROFILING_COMMAND_QUEUED:
00730             SIMPLE_ASSIGN(cl_ulong, p_timing[Queue]);
00731             break;
00732 
00733         case CL_PROFILING_COMMAND_SUBMIT:
00734             SIMPLE_ASSIGN(cl_ulong, p_timing[Submit]);
00735             break;
00736 
00737         case CL_PROFILING_COMMAND_START:
00738             SIMPLE_ASSIGN(cl_ulong, p_timing[Start]);
00739             break;
00740 
00741         case CL_PROFILING_COMMAND_END:
00742             SIMPLE_ASSIGN(cl_ulong, p_timing[End]);
00743             break;
00744 
00745         default:
00746             return CL_INVALID_VALUE;
00747     }
00748 
00749     if (param_value && param_value_size < value_length)
00750         return CL_INVALID_VALUE;
00751 
00752     if (param_value_size_ret)
00753         *param_value_size_ret = value_length;
00754 
00755     if (param_value)
00756         std::memcpy(param_value, value, value_length);
00757 
00758     return CL_SUCCESS;
00759 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines