| /* |
| * Copyright (c) 2015 Advanced Micro Devices, Inc. |
| * All rights reserved. |
| * |
| * For use for simulation and test purposes only |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * 3. Neither the name of the copyright holder nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Author: Marc Orr, Brad Beckmann |
| */ |
| |
| #include <CL/cl.h> |
| #include <malloc.h> |
| |
| #include <cstdio> |
| #include <cstring> |
| #include <fstream> |
| #include <string> |
| |
| #ifdef KVM_SWITCH |
| #include "m5op.h" |
| |
| void *m5_mem = (void*)0xffffc90000000000; |
| #endif |
| |
| #define SUCCESS 0 |
| #define FAILURE 1 |
| |
| // OpenCL datastructures |
| cl_context context; |
| cl_device_id *devices; |
| cl_command_queue commandQueue; |
| cl_program program; |
| cl_kernel readKernel; |
| |
| // Application datastructures |
| const int CACHE_LINE_SIZE = 64; |
| size_t grid_size = 512; |
| size_t work_group_size = 256; |
| |
| // arguments |
| const int code_size = 5; |
| const char *code = "hello"; |
| int *keys; |
| char *msg; |
| int chars_decoded = 0; |
| |
| /* |
| Setup data structures for application/algorithm |
| */ |
| int |
| setupDataStructs() |
| { |
| msg = (char *)memalign(CACHE_LINE_SIZE, (grid_size + 1) * sizeof(char)); |
| if (msg == NULL) { |
| printf("%s:%d: error: %s\n", __FILE__, __LINE__, |
| "could not allocate host buffers\n"); |
| exit(-1); |
| } |
| msg[grid_size] = '\0'; |
| |
| keys = (int *)memalign(CACHE_LINE_SIZE, code_size * sizeof(int)); |
| keys[0] = 23; |
| keys[1] = 0; |
| keys[2] = 0; |
| keys[3] = 0; |
| keys[4] = 0; |
| |
| return SUCCESS; |
| } |
| |
| /* Setup OpenCL data structures */ |
| int |
| setupOpenCL() |
| { |
| cl_int status = 0; |
| size_t deviceListSize; |
| |
| // 1. Get platform |
| cl_uint numPlatforms; |
| cl_platform_id platform = NULL; |
| status = clGetPlatformIDs(0, NULL, &numPlatforms); |
| if (status != CL_SUCCESS) { |
| printf("Error: Getting Platforms. (clGetPlatformsIDs)\n"); |
| return FAILURE; |
| } |
| |
| if (numPlatforms > 0) { |
| cl_platform_id *platforms = new cl_platform_id[numPlatforms]; |
| status = clGetPlatformIDs(numPlatforms, platforms, NULL); |
| if (status != CL_SUCCESS) { |
| printf("Error: Getting Platform Ids. (clGetPlatformsIDs)\n"); |
| return FAILURE; |
| } |
| for (int i = 0; i < numPlatforms; ++i) { |
| char pbuff[100]; |
| status = clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, |
| sizeof(pbuff), pbuff, NULL); |
| if (status != CL_SUCCESS) { |
| printf("Error: Getting Platform Info.(clGetPlatformInfo)\n"); |
| return FAILURE; |
| } |
| platform = platforms[i]; |
| if (!strcmp(pbuff, "Advanced Micro Devices, Inc.")) { |
| break; |
| } |
| } |
| delete platforms; |
| } |
| |
| if (NULL == platform) { |
| printf("NULL platform found so Exiting Application.\n"); |
| return FAILURE; |
| } |
| |
| // 2. create context from platform |
| cl_context_properties cps[3] = |
| {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0}; |
| context = clCreateContextFromType(cps, CL_DEVICE_TYPE_GPU, NULL, NULL, |
| &status); |
| if (status != CL_SUCCESS) { |
| printf("Error: Creating Context. (clCreateContextFromType)\n"); |
| return FAILURE; |
| } |
| |
| // 3. Get device info |
| // 3a. Get # of devices |
| status = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, |
| &deviceListSize); |
| if (status != CL_SUCCESS) { |
| printf("Error: Getting Context Info (1st clGetContextInfo)\n"); |
| return FAILURE; |
| } |
| |
| // 3b. Get the device list data |
| devices = (cl_device_id *)malloc(deviceListSize); |
| if (devices == 0) { |
| printf("Error: No devices found.\n"); |
| return FAILURE; |
| } |
| status = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceListSize, |
| devices, NULL); |
| if (status != CL_SUCCESS) { |
| printf("Error: Getting Context Info (2nd clGetContextInfo)\n"); |
| return FAILURE; |
| } |
| |
| // 4. Create command queue for device |
| commandQueue = clCreateCommandQueue(context, devices[0], 0, &status); |
| if (status != CL_SUCCESS) { |
| printf("Creating Command Queue. (clCreateCommandQueue)\n"); |
| return FAILURE; |
| } |
| |
| const char *source = "dummy text"; |
| |
| size_t sourceSize[] = {strlen(source)}; |
| |
| // 5b. Register the kernel with the runtime |
| program = clCreateProgramWithSource(context, 1, &source, sourceSize, |
| &status); |
| if (status != CL_SUCCESS) { |
| printf("Error: Loading kernel (clCreateProgramWithSource)\n"); |
| return FAILURE; |
| } |
| |
| status = clBuildProgram(program, 1, devices, NULL, NULL, NULL); |
| if (status != CL_SUCCESS) { |
| printf("Error: Building kernel (clBuildProgram)\n"); |
| return FAILURE; |
| } |
| |
| readKernel = clCreateKernel(program, "read_kernel", &status); |
| if (status != CL_SUCCESS) { |
| printf("Error: Creating readKernel from program. (clCreateKernel)\n"); |
| return FAILURE; |
| } |
| |
| return SUCCESS; |
| } |
| |
| |
| /* Run kernels */ |
| int |
| runCLKernel(cl_kernel kernel) |
| { |
| cl_int status; |
| cl_event event; |
| size_t globalThreads[1] = {grid_size}; |
| size_t localThreads[1] = {work_group_size}; |
| |
| // 1. Set arguments |
| // 1a. code size |
| size_t code_size = strlen(code); |
| status = clSetKernelArg(kernel, 0, sizeof(size_t), &code_size); |
| if (status != CL_SUCCESS) { |
| printf("Error: Setting kernel argument. (code_size)\n"); |
| return FAILURE; |
| } |
| |
| // 1b. code |
| status = clSetKernelArg(kernel, 1, sizeof(char *), (void *)&code); |
| if (status != CL_SUCCESS) { |
| printf("Error: Setting kernel argument. (code_in)\n"); |
| return FAILURE; |
| } |
| |
| // 1c. keys |
| printf("keys = %p, &keys = %p, keys[0] = %d\n", keys, &keys, keys[0]); |
| status = clSetKernelArg(kernel, 2, sizeof(int *), (void *)&keys); |
| if (status != CL_SUCCESS) { |
| printf("Error: Setting kernel argument. (key_arr)\n"); |
| return FAILURE; |
| } |
| |
| // 1d. msg |
| status = clSetKernelArg(kernel, 3, sizeof(char *), (void *)&msg); |
| if (status != CL_SUCCESS) { |
| printf("Error: Setting kernel argument. (memOut)\n"); |
| return FAILURE; |
| } |
| |
| // 1e. chars_decoded |
| int *chars_decoded_ptr = &chars_decoded; |
| status = clSetKernelArg(kernel, 4, sizeof(int *), |
| (void *)&chars_decoded_ptr); |
| if (status != CL_SUCCESS) { |
| printf("Error: Setting kernel argument. (memOut)\n"); |
| return FAILURE; |
| } |
| |
| #ifdef KVM_SWITCH |
| m5_switchcpu(); |
| #endif |
| |
| // 2. Launch kernel |
| status = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL, |
| globalThreads, localThreads, 0, NULL, |
| &event); |
| if (status != CL_SUCCESS) { |
| printf("Error: Enqueue failed. (clEnqueueNDRangeKernel)\n"); |
| return FAILURE; |
| } |
| |
| // 3. Wait for the kernel |
| status = clWaitForEvents(1, &event); |
| if (status != CL_SUCCESS) { |
| printf("Error: Waiting for kernel run to finish. (clWaitForEvents)\n"); |
| return FAILURE; |
| } |
| |
| // 4. Cleanup |
| status = clReleaseEvent(event); |
| if (status != CL_SUCCESS) { |
| printf("Error: Release event object. (clReleaseEvent)\n"); |
| return FAILURE; |
| } |
| |
| return SUCCESS; |
| } |
| |
| |
| /* Release OpenCL resources (Context, Memory etc.) */ |
| int |
| cleanupCL() |
| { |
| cl_int status; |
| status = clReleaseKernel(readKernel); |
| if (status != CL_SUCCESS) { |
| printf("Error: In clReleaseKernel \n"); |
| return FAILURE; |
| } |
| status = clReleaseProgram(program); |
| if (status != CL_SUCCESS) { |
| printf("Error: In clReleaseProgram\n"); |
| return FAILURE; |
| } |
| status = clReleaseCommandQueue(commandQueue); |
| if (status != CL_SUCCESS) { |
| printf("Error: In clReleaseCommandQueue\n"); |
| return FAILURE; |
| } |
| status = clReleaseContext(context); |
| if (status != CL_SUCCESS) { |
| printf("Error: In clReleaseContext\n"); |
| return FAILURE; |
| } |
| |
| return SUCCESS; |
| } |
| |
| int |
| main(int argc, char * argv[]) |
| { |
| // Initialize Host application |
| if (setupDataStructs() != SUCCESS) { |
| return FAILURE; |
| } |
| |
| // Initialize OpenCL resources |
| if (setupOpenCL() != SUCCESS) { |
| return FAILURE; |
| } |
| |
| // Run the CL program |
| if (runCLKernel(readKernel) != SUCCESS) { |
| return FAILURE; |
| } |
| printf("the gpu says:\n"); |
| printf("%s\n", msg); |
| |
| // Releases OpenCL resources |
| if (cleanupCL()!= SUCCESS) { |
| return FAILURE; |
| } |
| |
| return SUCCESS; |
| } |