Clover Git
OpenCL 1.1 software implementation
|
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 }