/* Copyright (c) 2010 - 2021 Advanced Micro Devices, Inc. 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 #define CL_USE_DEPRECATED_OPENCL_2_0_APIS 1 #include "CL/cl.hpp" SERVICE_STATUS serviceStatus = {0}; SERVICE_STATUS_HANDLE serviceStatusHandle = 0; const wchar_t* CrossProcessEventName = L"Global\\OpenCL_Test_serviceEvent"; const wchar_t* successMessage = L"OpenCL Service Test Success\n"; const wchar_t* serviceName = L"OpenCL Test service"; // this event is set whenever the service thread is finished executing // all it's tasks HANDLE RetireServiceEvent = 0; DWORD WINAPI ThreadProc(LPVOID lpdwThreadParam); ////////////////////////// // log relate functions // ////////////////////////// void getLogFileName(wchar_t fileName[MAX_PATH]) { DWORD dwSize = GetModuleFileNameW(NULL, fileName, MAX_PATH); wchar_t* p = fileName + dwSize; while (*p != '\\' && p > fileName) p--; p++; wcscpy(p, L"result.txt"); } VOID WriteLog(const wchar_t* pMsg) { static wchar_t fileName[MAX_PATH] = {0}; if (fileName[0] == 0) getLogFileName(fileName); FILE* pLog = _wfopen(fileName, L"w"); if (NULL != pLog) { fwprintf(pLog, pMsg); fclose(pLog); } } VOID AppendLog(const wchar_t* pMsg) { static wchar_t fileName[MAX_PATH] = {0}; if (fileName[0] == 0) getLogFileName(fileName); FILE* pLog = _wfopen(fileName, L"a"); if (NULL != pLog) { fwprintf(pLog, pMsg); fclose(pLog); } } VOID AppendLog(const char* pMsg) { static wchar_t fileName[MAX_PATH] = {0}; if (fileName[0] == 0) getLogFileName(fileName); FILE* pLog = _wfopen(fileName, L"a"); if (NULL != pLog) { fprintf(pLog, pMsg); fclose(pLog); } } /////////////////////////////// // service related functions // /////////////////////////////// void WINAPI ServiceControlHandler(DWORD controlCode) { switch (controlCode) { case SERVICE_CONTROL_INTERROGATE: break; case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) AppendLog(L"SetServiceStatus SERVICE_STOP_PENDING failed\n"); if (RetireServiceEvent) SetEvent(RetireServiceEvent); return; case SERVICE_CONTROL_PAUSE: break; case SERVICE_CONTROL_CONTINUE: break; default: if (controlCode >= 128 && controlCode <= 255) // user defined control code break; else // unrecognised control code break; } if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) AppendLog(L"SetServiceStatus SERVICE_STOP_PENDING failed\n"); } void WINAPI ServiceMain(DWORD /*argc*/, wchar_t* /*argv*/[]) { // initialise service status serviceStatus.dwServiceType = SERVICE_WIN32; serviceStatus.dwCurrentState = SERVICE_START_PENDING; serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN; serviceStatus.dwWin32ExitCode = NO_ERROR; serviceStatus.dwServiceSpecificExitCode = NO_ERROR; serviceStatus.dwCheckPoint = 0; serviceStatus.dwWaitHint = 0; serviceStatusHandle = RegisterServiceCtrlHandlerW(serviceName, ServiceControlHandler); if (serviceStatusHandle) { // service is starting serviceStatus.dwCurrentState = SERVICE_START_PENDING; if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) AppendLog(L"SetServiceStatus SERVICE_START_PENDING failed\n"); // do initialisation here RetireServiceEvent = CreateEvent(0, FALSE, FALSE, 0); // running serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); serviceStatus.dwCurrentState = SERVICE_RUNNING; if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) AppendLog(L"SetServiceStatus SERVICE_RUNNING failed\n"); // Create the thread that actually does the CL testing CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); // wait for the thread to finish WaitForSingleObject(RetireServiceEvent, 60000); HANDLE crossProcessEvent = OpenEventW(EVENT_ALL_ACCESS, FALSE, CrossProcessEventName); if (NULL != crossProcessEvent) { SetEvent(crossProcessEvent); } else { AppendLog(L"cross process Event could not be openned\n"); } // service was stopped serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) AppendLog(L"SetServiceStatus SERVICE_STOP_PENDING failed\n"); // do cleanup here CloseHandle(crossProcessEvent); CloseHandle(RetireServiceEvent); RetireServiceEvent = 0; // service is now stopped serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); serviceStatus.dwCurrentState = SERVICE_STOPPED; if (!SetServiceStatus(serviceStatusHandle, &serviceStatus)) AppendLog(L"SetServiceStatus SERVICE_STOPPED failed\n"); } } // This function services ocltst as a service when launched // by the OS. It registers the service routines. void serviceStubCall() { wchar_t serviceName[MAX_PATH]; wcscpy(serviceName, ::serviceName); SERVICE_TABLE_ENTRYW serviceTable[] = {{serviceName, ServiceMain}, {0, 0}}; DWORD session_id; BOOL retVal = ProcessIdToSessionId(GetCurrentProcessId(), &session_id); if (0 == session_id) { StartServiceCtrlDispatcherW(serviceTable); } } ///////////////////// // CL related code // ///////////////////// const char c_kernelCode[] = " __kernel void hello(__global char * theArray)" "{" " size_t i = get_global_id(0);" "if ( i < get_global_size(0))" "theArray[i] = 78;" "}"; const unsigned int c_bufferSize = 1024; DWORD WINAPI ThreadProc(LPVOID lpdwThreadParam) { cl_int err; // Platform info std::vector platforms; err = cl::Platform::get(&platforms); if (err != CL_SUCCESS) { AppendLog(L"Platform::get() failed\n"); return -1; } std::vector::iterator i; if (platforms.size() > 0) { for (i = platforms.begin(); i != platforms.end(); ++i) { if (!strcmp((*i).getInfo(&err).c_str(), "Advanced Micro Devices, Inc.")) { break; } } } if (err != CL_SUCCESS) { AppendLog(L"Platform::getInfo() failed \n"); return -1; } cl_context_properties cps[3] = {CL_CONTEXT_PLATFORM, (cl_context_properties)(*i)(), 0}; cl::Context context(CL_DEVICE_TYPE_GPU, cps, NULL, NULL, &err); if (err != CL_SUCCESS) { AppendLog(L"Context::Context() failed \n"); return -1; } std::vector devices = context.getInfo(); if (err != CL_SUCCESS) { AppendLog(L"Context::getInfo() failed \n"); return -1; } if (devices.size() == 0) { AppendLog(L"No device available\n"); return -1; } cl::Program::Sources sources(1, std::make_pair(c_kernelCode, sizeof(c_kernelCode))); cl::Program program = cl::Program(context, sources, &err); if (err != CL_SUCCESS) { AppendLog(L"Program::Program() failed\n"); } err = program.build(devices); if (err != CL_SUCCESS) { if (err == CL_BUILD_PROGRAM_FAILURE) { std::string str((char*)program.getBuildInfo(devices[0]).c_str()); AppendLog(L" \n\t\t\tBUILD LOG\n\n"); AppendLog(L" ************************************************\n"); AppendLog(str.c_str()); AppendLog(L" ************************************************\n"); } AppendLog(L"Program::build() failed\n"); return -1; } cl::Kernel kernel(program, "hello", &err); if (err != CL_SUCCESS) { AppendLog(L"Kernel::Kernel() failed\n"); return -1; } cl::Buffer buffer = cl::Buffer(context, CL_MEM_READ_WRITE, c_bufferSize, 0, &err); if (err != CL_SUCCESS) { AppendLog(L"Kernel::setArg() failed \n"); } cl::CommandQueue queue(context, devices[0], 0, &err); if (err != CL_SUCCESS) { AppendLog(L"CommandQueue::CommandQueue() failed \n"); return -1; } err = kernel.setArg(0, buffer); if (err != CL_SUCCESS) { AppendLog(L"Kernel::setArg() failed \n"); return -1; } err = queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(c_bufferSize), cl::NullRange); if (err != CL_SUCCESS) { AppendLog(L"CommandQueue::enqueueNDRangeKernel()\n"); return -1; } err = queue.finish(); if (err != CL_SUCCESS) { AppendLog(L"Event::wait() failed \n"); } char* ptr = (char*)malloc(c_bufferSize); err = queue.enqueueReadBuffer(buffer, CL_TRUE, 0, c_bufferSize, ptr, NULL, NULL); if (err != CL_SUCCESS) { AppendLog(L"CommandQueue::enqueueReadBuffer()\n"); return -1; } bool validateSuccess = true; // validate the results for (int i = 0; i < c_bufferSize; i++) { if (ptr[i] != 78) validateSuccess = false; } free(ptr); if (validateSuccess) { WriteLog(successMessage); AppendLog(L"validate success"); } else { AppendLog(L"Validate fail"); return -1; } SetEvent(RetireServiceEvent); return 0; }