blob: bdff074a8cad33486aac2827e8dc0fa4199c1555 [file] [log] [blame]
/*
* 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;
}