/* * Copyright (c) Advanced Micro Devices, Inc., or its affiliates. * * SPDX-License-Identifier: MIT */ #include "OCLThreadTrace.h" #include #include #include #include "CL/cl.h" const static unsigned int IOThreadTrace = 3; // number of input/oputput buffers static size_t SeNum = 1; // number of SEs // size of thread trace buffer #if EMU_ENV const static unsigned int ttBufSize = 5000; #else const static unsigned int ttBufSize = 30000; #endif const static unsigned int InputElements = 2048; // elements in each vector const static char* strKernel = "__kernel void thread_trace_test( \n" " __global int *A,__global int *B,__global int *C) \n" "{ \n" " int idx = get_global_id(0); \n" " C[idx] = A[idx] + B[idx]; \n" "} \n"; OCLThreadTrace::OCLThreadTrace() { _numSubTests = 1; failed_ = false; clCreateThreadTraceAMD_ = 0; clReleaseThreadTraceAMD_ = 0; clRetainThreadTraceAMD_ = 0; clGetThreadTraceInfoAMD_ = 0; clSetThreadTraceParamAMD_ = 0; clEnqueueThreadTraceCommandAMD_ = 0; clEnqueueBindThreadTraceBufferAMD_ = 0; ioBuf_ = 0; ttBuf_ = 0; } OCLThreadTrace::~OCLThreadTrace() {} void OCLThreadTrace::open(unsigned int test, char* units, double& conversion, unsigned int deviceId) { OCLTestImp::open(test, units, conversion, deviceId); CHECK_RESULT((error_ != CL_SUCCESS), "Error opening"); if (deviceId >= deviceCount_) { failed_ = true; return; } cl_device_type deviceType; error_ = _wrapper->clGetDeviceInfo(devices_[deviceId], CL_DEVICE_TYPE, sizeof(deviceType), &deviceType, NULL); CHECK_RESULT((error_ != CL_SUCCESS), "CL_DEVICE_TYPE failed"); if (!(deviceType & CL_DEVICE_TYPE_GPU)) { printf("GPU device is required for this test!\n"); failed_ = true; return; } size_t threadTraceEnabled; size_t retsize; error_ = _wrapper->clGetDeviceInfo(devices_[deviceId], CL_DEVICE_THREAD_TRACE_SUPPORTED_AMD, sizeof(threadTraceEnabled), &threadTraceEnabled, &retsize); CHECK_RESULT(error_ != CL_SUCCESS, "clGetDeviceInfo failed"); if (!threadTraceEnabled) { failed_ = true; testDescString = "Not supported"; return; } unsigned int datasize = sizeof(unsigned int) * InputElements; ioBuf_ = (unsigned int**)malloc(IOThreadTrace * sizeof(unsigned int*)); CHECK_RESULT((ioBuf_ == NULL), "malloc failed"); memset(ioBuf_, 0, IOThreadTrace * sizeof(unsigned int*)); for (unsigned i = 0; i < IOThreadTrace; ++i) { ioBuf_[i] = (unsigned int*)malloc(datasize); CHECK_RESULT((ioBuf_[i] == NULL), "malloc failed"); for (unsigned j = 0; j < InputElements; ++j) { ioBuf_[i][j] = j; } } clCreateThreadTraceAMD_ = (fnp_clCreateThreadTraceAMD)_wrapper->clGetExtensionFunctionAddress("clCreateThreadTraceAMD"); CHECK_RESULT((clCreateThreadTraceAMD_ == 0), "clGetExtensionFunctionAddress(clCreateThreadTraceAMD) failed"); clGetThreadTraceInfoAMD_ = (fnp_clGetThreadTraceInfoAMD)_wrapper->clGetExtensionFunctionAddress( "clGetThreadTraceInfoAMD"); CHECK_RESULT((clGetThreadTraceInfoAMD_ == 0), "clGetExtensionFunctionAddress(clGetThreadTraceInfoAMD) failed"); threadTrace_ = clCreateThreadTraceAMD_(devices_[_deviceId], &error_); CHECK_RESULT((error_ != CL_SUCCESS), "clCreateThreadTraceAMD() failed"); // Get number of shader engines clGetThreadTraceInfoAMD_(threadTrace_, CL_THREAD_TRACE_SE, sizeof(SeNum), &SeNum, NULL); ttBuf_ = (unsigned int**)malloc(SeNum * sizeof(unsigned int*)); CHECK_RESULT((ttBuf_ == NULL), "malloc failed"); memset(ttBuf_, 0, SeNum * sizeof(unsigned int*)); program_ = _wrapper->clCreateProgramWithSource(context_, 1, &strKernel, NULL, &error_); CHECK_RESULT((error_ != CL_SUCCESS), "clCreateProgramWithSource() failed"); error_ = _wrapper->clBuildProgram(program_, 1, &devices_[deviceId], NULL, NULL, NULL); if (error_ != CL_SUCCESS) { char programLog[1024]; _wrapper->clGetProgramBuildInfo(program_, devices_[deviceId], CL_PROGRAM_BUILD_LOG, 1024, programLog, 0); printf("\n%s\n", programLog); fflush(stdout); } CHECK_RESULT((error_ != CL_SUCCESS), "clBuildProgram() failed"); kernel_ = _wrapper->clCreateKernel(program_, "thread_trace_test", &error_); CHECK_RESULT((error_ != CL_SUCCESS), "clCreateKernel() failed"); cl_mem buffer; for (unsigned int i = 0; i < IOThreadTrace; ++i) { buffer = _wrapper->clCreateBuffer(context_, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, datasize, ioBuf_[i], &error_); CHECK_RESULT((error_ != CL_SUCCESS), "clCreateBuffer() failed"); buffers_.push_back(buffer); } for (unsigned int i = 0; i < SeNum; ++i) { buffer = _wrapper->clCreateBuffer(context_, CL_MEM_READ_WRITE, ttBufSize, NULL, &error_); CHECK_RESULT((error_ != CL_SUCCESS), "clCreateBuffer() failed"); buffers_.push_back(buffer); } clReleaseThreadTraceAMD_ = (fnp_clReleaseThreadTraceAMD)_wrapper->clGetExtensionFunctionAddress( "clReleaseThreadTraceAMD"); CHECK_RESULT((clReleaseThreadTraceAMD_ == 0), "clGetExtensionFunctionAddress(clReleaseThreadTraceAMD) failed"); clRetainThreadTraceAMD_ = (fnp_clRetainThreadTraceAMD)_wrapper->clGetExtensionFunctionAddress("clRetainThreadTraceAMD"); CHECK_RESULT((clRetainThreadTraceAMD_ == 0), "clGetExtensionFunctionAddress(clRetainThreadTraceAMD) failed"); clSetThreadTraceParamAMD_ = (fnp_clSetThreadTraceParamAMD)_wrapper->clGetExtensionFunctionAddress( "clSetThreadTraceParamAMD"); CHECK_RESULT((clSetThreadTraceParamAMD_ == 0), "clGetExtensionFunctionAddress(clSetThreadTraceParamAMD) failed"); clEnqueueThreadTraceCommandAMD_ = (fnp_clEnqueueThreadTraceCommandAMD)_wrapper->clGetExtensionFunctionAddress( "clEnqueueThreadTraceCommandAMD"); CHECK_RESULT((clEnqueueThreadTraceCommandAMD_ == 0), "clGetExtensionFunctionAddress(clEnqueueThreadTraceCommandAMD) failed"); clEnqueueBindThreadTraceBufferAMD_ = (fnp_clEnqueueBindThreadTraceBufferAMD)_wrapper->clGetExtensionFunctionAddress( "clEnqueueBindThreadTraceBufferAMD"); CHECK_RESULT((clEnqueueBindThreadTraceBufferAMD_ == 0), "clGetExtensionFunctionAddress(" "clEnqueueBindThreadTraceBufferAMD) failed"); } static void CL_CALLBACK notify_callback(const char* errinfo, const void* private_info, size_t cb, void* user_data) {} static void DumpTraceSI(unsigned int index, cl_ushort* tracePtr, size_t numOfBytes) { FILE* outFile; char file_name[31] = {0}; static unsigned int iii = 0; snprintf(file_name, sizeof(file_name), "TTrace%d%d.out", index, iii++); outFile = fopen(file_name, "w"); for (size_t i = 0; i < numOfBytes / 2; i++) { fprintf(outFile, "%04x\n", (cl_ushort)(*tracePtr)); tracePtr++; } fclose(outFile); } #define DUMPTRACE 0 void OCLThreadTrace::run(void) { cl_mem* ttArrBuf = 0; unsigned int* ttBufRecordedSizes = 0; unsigned int i = 0, j = 0; if (failed_) { return; } for (i = 0; i < IOThreadTrace; ++i) { cl_mem buffer = buffers()[i]; error_ = _wrapper->clSetKernelArg(kernel_, i, sizeof(cl_mem), &buffer); CHECK_RESULT((error_ != CL_SUCCESS), "clSetKernelArg() failed"); } size_t globalWorkSize[1]; size_t localWorkSize[1]; globalWorkSize[0] = InputElements; localWorkSize[0] = 32; ttArrBuf = (cl_mem*)malloc(sizeof(cl_mem) * SeNum); ; for (i = 0; i < SeNum; i++) ttArrBuf[i] = buffers()[IOThreadTrace + i]; cl_event clEvent; error_ = clEnqueueBindThreadTraceBufferAMD_(cmdQueues_[_deviceId], threadTrace_, ttArrBuf, (cl_uint)SeNum, ttBufSize, 0, NULL, &clEvent); CHECK_RESULT((error_ != CL_SUCCESS), "clEnqueueBindThreadTraceBufferAMD() failed"); error_ = clEnqueueThreadTraceCommandAMD_(cmdQueues_[_deviceId], threadTrace_, CL_THREAD_TRACE_BEGIN_COMMAND, 0, NULL, &clEvent); CHECK_RESULT((error_ != CL_SUCCESS), "clEnqueueThreadTraceCommandAMD() failed"); error_ = _wrapper->clEnqueueNDRangeKernel(cmdQueues_[_deviceId], kernel_, 1, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL); CHECK_RESULT((error_ != CL_SUCCESS), "clEnqueueNDRangeKernel() failed"); clFinish(cmdQueues_[_deviceId]); error_ = clEnqueueThreadTraceCommandAMD_(cmdQueues_[_deviceId], threadTrace_, CL_THREAD_TRACE_END_COMMAND, 0, NULL, &clEvent); CHECK_RESULT((error_ != CL_SUCCESS), "clEnqueueThreadTraceCommandAMD() failed"); ttBufRecordedSizes = (unsigned int*)malloc(sizeof(unsigned int) * SeNum); memset(ttBufRecordedSizes, 0, sizeof(unsigned int) * SeNum); size_t ttBufRecordedSize; error_ = clGetThreadTraceInfoAMD_(threadTrace_, CL_THREAD_TRACE_BUFFERS_SIZE, 1, NULL, &ttBufRecordedSize); CHECK_RESULT((error_ != CL_SUCCESS), "clGetThreadTraceInfoAMD() failed"); if (ttBufRecordedSize > sizeof(unsigned int) * SeNum) { free(ttBufRecordedSizes); ttBufRecordedSizes = (unsigned int*)malloc(ttBufRecordedSize); memset(ttBufRecordedSizes, 0, ttBufRecordedSize); } error_ = clGetThreadTraceInfoAMD_(threadTrace_, CL_THREAD_TRACE_BUFFERS_SIZE, ttBufRecordedSize, ttBufRecordedSizes, NULL); CHECK_RESULT((error_ != CL_SUCCESS), "clGetThreadTraceInfoAMD() failed"); for (i = 0; i < SeNum; ++i) { ttBuf_[i] = (cl_uint*)malloc(ttBufRecordedSizes[i] * sizeof(cl_uint)); CHECK_RESULT((ttBuf_[i] == NULL), "malloc failed"); } for (i = 0; i < SeNum; ++i) { if (ttBufRecordedSizes[i] != 0) { error_ = _wrapper->clEnqueueReadBuffer(cmdQueues_[_deviceId], buffers()[IOThreadTrace + i], CL_TRUE, 0, ttBufRecordedSizes[i], ttBuf_[i], 0, NULL, NULL); CHECK_RESULT((error_ != CL_SUCCESS), "clEnqueueReadBuffer() failed"); #if DUMPTRACE DumpTraceSI(i, (cl_ushort*)ttBuf_[i], ttBufRecordedSizes[i]); #endif } } bool validRes = true; for (i = 0; i < SeNum; ++i) { unsigned j; for (j = 0; j < ttBufRecordedSizes[i]; ++j) { if (ttBuf_[i][j] != 0) { break; } } if (j >= ttBufRecordedSizes[i] && ttBufRecordedSizes[i] > 0) { validRes = false; break; } } if (!validRes) { CHECK_RESULT(true, " - Incorrect result for thread trace. no output data was recorded.\n"); } if (ttArrBuf) free(ttArrBuf); if (ttBufRecordedSizes) free(ttBufRecordedSizes); } unsigned int OCLThreadTrace::close(void) { if (clReleaseThreadTraceAMD_ && threadTrace_) clReleaseThreadTraceAMD_(threadTrace_); if (ioBuf_) { for (unsigned i = 0; i < IOThreadTrace; ++i) { if (ioBuf_[i]) { free(ioBuf_[i]); } } free(ioBuf_); } if (ttBuf_) { for (unsigned i = 0; i < SeNum; ++i) { if (ttBuf_[i]) { free(ttBuf_[i]); } } free(ttBuf_); } return OCLTestImp::close(); }