| /* | |
| * 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; | |
| } |