From 7b0f416f8980577f942c14d2caae050e809b2053 Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Fri, 18 Sep 2026 07:34:41 -0700 Subject: [PATCH] add the ability to log kernel argument info --- docs/controls.md | 4 + intercept/src/controls.h | 1 + intercept/src/dispatch.cpp | 2 + intercept/src/intercept.cpp | 333 +++++++++++++++++++++++++----------- intercept/src/intercept.h | 5 + 5 files changed, 242 insertions(+), 103 deletions(-) diff --git a/docs/controls.md b/docs/controls.md index 3ebe17c7..42429914 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -169,6 +169,10 @@ If set to a nonzero value, logs the preferred work group size multiple for each If set to a nonzero value, logs information about the kernel after each call to clCreateKernel(). +##### `KernelArgInfoLogging` (bool) + +If set to a nonzero value, logs information about kernel arguments after each call to clCreateKernel(). + ##### `CallLogging` (bool) If set to a nonzero value, logs function entry and exit information for every OpenCL call. This can be used to easily determine which OpenCL call is causing an application to crash or fail or if a crash occurs outside of an OpenCL call. This setting is best used with LogToFile or LogToDebugger as it can generate a lot of log data. diff --git a/intercept/src/controls.h b/intercept/src/controls.h index 8813ab61..4ad33795 100644 --- a/intercept/src/controls.h +++ b/intercept/src/controls.h @@ -24,6 +24,7 @@ CLI_CONTROL( int, LogIndent, 0, "Inde CLI_CONTROL( bool, BuildLogging, false, "If set to a nonzero value, logs the program build log after each call to clBuildProgram(). This will likely only function correctly for synchronous builds. Note that the build log is logged regardless of whether the program built successfully, which allows compiler warnings to be logged for successful compiles." ) CLI_CONTROL( bool, PreferredWorkGroupSizeMultipleLogging, false, "If set to a nonzero value, logs the preferred work group size multiple for each kernel after each call to clCreateKernel(). On some devices this is the equivalent of the SIMD size for this kernel." ) CLI_CONTROL( bool, KernelInfoLogging, false, "If set to a nonzero value, logs information about the kernel after each call to clCreateKernel()." ) +CLI_CONTROL( bool, KernelArgInfoLogging, false, "If set to a nonzero value, logs information about kernel arguments after each call to clCreateKernel()." ) CLI_CONTROL( bool, CallLogging, false, "If set to a nonzero value, logs function entry and exit information for every OpenCL call. This can be used to easily determine which OpenCL call is causing an application to crash or fail or if a crash occurs outside of an OpenCL call. This setting is best used with LogToFile or LogToDebugger as it can generate a lot of log data." ) CLI_CONTROL( bool, CallLoggingEnqueueCounter, false, "If set to a nonzero value, logs the enqueue counter in addition to function entry and exit information for every OpenCL call. This can be used to determine appropriate limits for DumpBuffersMinEnqueue, DumpBuffersMaxEnqueue, DumpImagesMinEnqueue, or DumpBuffersMaxEnqueue. If CallLogging is disabled then this control will have no effect." ) CLI_CONTROL( bool, CallLoggingThreadId, false, "If set to a nonzero value, logs the ID of the calling thread in addition to function entry and exit information for every OpenCL call. This can be helpful when debugging multi-threading issues." ) diff --git a/intercept/src/dispatch.cpp b/intercept/src/dispatch.cpp index c0d443ac..02e8cab1 100644 --- a/intercept/src/dispatch.cpp +++ b/intercept/src/dispatch.cpp @@ -2723,6 +2723,7 @@ CL_API_ENTRY cl_kernel CL_API_CALL CLIRN(clCreateKernel)( program, kernel_name ); if( pIntercept->config().KernelInfoLogging || + pIntercept->config().KernelArgInfoLogging || pIntercept->config().PreferredWorkGroupSizeMultipleLogging ) { pIntercept->logKernelInfo( @@ -2799,6 +2800,7 @@ CL_API_ENTRY cl_int CL_API_CALL CLIRN(clCreateKernelsInProgram)( program, num_kernels_ret[0] ); if( pIntercept->config().KernelInfoLogging || + pIntercept->config().KernelArgInfoLogging || pIntercept->config().PreferredWorkGroupSizeMultipleLogging ) { pIntercept->logKernelInfo( diff --git a/intercept/src/intercept.cpp b/intercept/src/intercept.cpp index 2b910434..4f160893 100644 --- a/intercept/src/intercept.cpp +++ b/intercept/src/intercept.cpp @@ -1733,6 +1733,46 @@ cl_int CLIntercept::getKernelInfoString( return errorCode; } +/////////////////////////////////////////////////////////////////////////////// +// +cl_int CLIntercept::getKernelArgInfoString( + cl_kernel kernel, + cl_uint arg_index, + cl_kernel_arg_info param_name, + std::string& str ) const +{ + cl_int errorCode = CL_SUCCESS; + size_t size = 0; + + errorCode = dispatch().clGetKernelArgInfo( + kernel, + arg_index, + param_name, + 0, + nullptr, + &size ); + + if( errorCode == CL_SUCCESS ) + { + str.assign( size, ' ' ); + errorCode = dispatch().clGetKernelArgInfo( + kernel, + arg_index, + param_name, + size, + &str[0], + nullptr ); + str.pop_back(); // remove the NUL terminator + } + + if( errorCode != CL_SUCCESS ) + { + str.clear(); + } + + return errorCode; +} + /////////////////////////////////////////////////////////////////////////////// // cl_int CLIntercept::allocateAndGetProgramDeviceList( @@ -3541,119 +3581,207 @@ void CLIntercept::logKernelInfo( cl_kernel kernel = kernels[ numKernels ]; const std::string& kernelName = getShortKernelNameWithHash(kernel); - log( "Kernel Info for: " + kernelName + "\n" ); - for( cl_uint i = 0; i < numDevices; i++ ) + if( config().KernelInfoLogging || + config().PreferredWorkGroupSizeMultipleLogging ) { - std::string deviceName; - errorCode = getDeviceInfoString( - deviceList[i], - CL_DEVICE_NAME, - deviceName ); + log( "Kernel Info for: " + kernelName + "\n" ); - cl_uint args = 0; - errorCode |= dispatch().clGetKernelInfo( - kernel, - CL_KERNEL_NUM_ARGS, - sizeof(args), - &args, - NULL ); - - size_t pwgsm = 0; - errorCode |= dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, - sizeof(pwgsm), - &pwgsm, - NULL ); - size_t wgs = 0; - errorCode |= dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_WORK_GROUP_SIZE, - sizeof(wgs), - &wgs, - NULL ); - size_t rwgs[3] = {0, 0, 0}; - errorCode |= dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_COMPILE_WORK_GROUP_SIZE, - sizeof(rwgs), - rwgs, - NULL ); - cl_ulong pms = 0; - errorCode |= dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_PRIVATE_MEM_SIZE, - sizeof(pms), - &pms, - NULL ); - cl_ulong lms = 0; - errorCode |= dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_LOCAL_MEM_SIZE, - sizeof(lms), - &lms, - NULL ); - cl_ulong sms = 0; - cl_int errorCode_sms = dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_SPILL_MEM_SIZE_INTEL, - sizeof(sms), - &sms, - NULL ); - cl_uint regCount = 0; - cl_int errorCode_regCount = dispatch().clGetKernelWorkGroupInfo( - kernel, - deviceList[i], - CL_KERNEL_REGISTER_COUNT_INTEL, - sizeof(regCount), - ®Count, - NULL ); - if( errorCode == CL_SUCCESS ) + for( cl_uint i = 0; i < numDevices; i++ ) { - logf( " For device: %s\n", deviceName.c_str() ); - if( config().KernelInfoLogging ) - { - logf( " Num Args: %u\n", args); - } - if( config().KernelInfoLogging || - config().PreferredWorkGroupSizeMultipleLogging ) - { - logf( " Preferred Work Group Size Multiple: %zu\n", pwgsm); - } - if( config().KernelInfoLogging ) + std::string deviceName; + errorCode = getDeviceInfoString( + deviceList[i], + CL_DEVICE_NAME, + deviceName ); + + cl_uint args = 0; + errorCode |= dispatch().clGetKernelInfo( + kernel, + CL_KERNEL_NUM_ARGS, + sizeof(args), + &args, + NULL ); + + size_t pwgsm = 0; + errorCode |= dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, + sizeof(pwgsm), + &pwgsm, + NULL ); + size_t wgs = 0; + errorCode |= dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_WORK_GROUP_SIZE, + sizeof(wgs), + &wgs, + NULL ); + size_t rwgs[3] = {0, 0, 0}; + errorCode |= dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_COMPILE_WORK_GROUP_SIZE, + sizeof(rwgs), + rwgs, + NULL ); + cl_ulong pms = 0; + errorCode |= dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_PRIVATE_MEM_SIZE, + sizeof(pms), + &pms, + NULL ); + cl_ulong lms = 0; + errorCode |= dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_LOCAL_MEM_SIZE, + sizeof(lms), + &lms, + NULL ); + cl_ulong sms = 0; + cl_int errorCode_sms = dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_SPILL_MEM_SIZE_INTEL, + sizeof(sms), + &sms, + NULL ); + cl_uint regCount = 0; + cl_int errorCode_regCount = dispatch().clGetKernelWorkGroupInfo( + kernel, + deviceList[i], + CL_KERNEL_REGISTER_COUNT_INTEL, + sizeof(regCount), + ®Count, + NULL ); + if( errorCode == CL_SUCCESS ) { - logf( " Max Work Group Size: %zu\n", wgs); - if( rwgs[0] != 0 || rwgs[1] != 0 || rwgs[2] != 0 ) + logf( " For device: %s\n", deviceName.c_str() ); + if( config().KernelInfoLogging ) { - logf( " Required Work Group Size: < %zu, %zu, %zu >\n", - rwgs[0], rwgs[1], rwgs[2]); + logf( " Num Args: %u\n", args); } - logf( " Private Mem Size: %u\n", (cl_uint)pms); - logf( " Local Mem Size: %u\n", (cl_uint)lms); - if( errorCode_sms == CL_SUCCESS ) + if( config().KernelInfoLogging || + config().PreferredWorkGroupSizeMultipleLogging ) { - logf( " Spill Mem Size: %u\n", (cl_uint)sms); + logf( " Preferred Work Group Size Multiple: %zu\n", pwgsm); } - if( errorCode_regCount == CL_SUCCESS ) + if( config().KernelInfoLogging ) { - logf( " Register Count: %u\n", regCount); + logf( " Max Work Group Size: %zu\n", wgs); + if( rwgs[0] != 0 || rwgs[1] != 0 || rwgs[2] != 0 ) + { + logf( " Required Work Group Size: < %zu, %zu, %zu >\n", + rwgs[0], rwgs[1], rwgs[2]); + } + logf( " Private Mem Size: %u\n", (cl_uint)pms); + logf( " Local Mem Size: %u\n", (cl_uint)lms); + if( errorCode_sms == CL_SUCCESS ) + { + logf( " Spill Mem Size: %u\n", (cl_uint)sms); + } + if( errorCode_regCount == CL_SUCCESS ) + { + logf( " Register Count: %u\n", regCount); + } } } + else if( !deviceName.empty() ) + { + logf( "Error querying kernel info for device %s!\n", deviceName.c_str() ); + } + else + { + logf( "Error querying kernel info!\n" ); + } } - else if( !deviceName.empty() ) + } + + if( config().KernelArgInfoLogging ) + { + cl_uint args = 0; + errorCode = dispatch().clGetKernelInfo( + kernel, + CL_KERNEL_NUM_ARGS, + sizeof(args), + &args, + NULL ); + if( errorCode != CL_SUCCESS ) { - logf( "Error querying kernel info for device %s!\n", deviceName.c_str() ); + logf( "Error querying number of kernel arguments!\n" ); } else { - logf( "Error querying kernel info!\n" ); + log( "Kernel Arg Info for: " + kernelName + "\n" ); + + for( cl_uint i = 0; i < args; i++ ) + { + std::string typeName; + errorCode = getKernelArgInfoString( + kernel, + i, + CL_KERNEL_ARG_TYPE_NAME, + typeName ); + + std::string argName; + errorCode |= getKernelArgInfoString( + kernel, + i, + CL_KERNEL_ARG_NAME, + argName ); + + cl_kernel_arg_type_qualifier typeQualifier = + CL_KERNEL_ARG_TYPE_NONE; + dispatch().clGetKernelArgInfo( + kernel, + i, + CL_KERNEL_ARG_TYPE_QUALIFIER, + sizeof(typeQualifier), + &typeQualifier, + nullptr ); + + cl_kernel_arg_address_qualifier addressQualifier = + CL_KERNEL_ARG_ADDRESS_PRIVATE; + dispatch().clGetKernelArgInfo( + kernel, + i, + CL_KERNEL_ARG_ADDRESS_QUALIFIER, + sizeof(addressQualifier), + &addressQualifier, + nullptr ); + + cl_kernel_arg_access_qualifier accessQualifier = + CL_KERNEL_ARG_ACCESS_NONE; + dispatch().clGetKernelArgInfo( + kernel, + i, + CL_KERNEL_ARG_ACCESS_QUALIFIER, + sizeof(accessQualifier), + &accessQualifier, + nullptr ); + + if( errorCode == CL_SUCCESS ) + { + logf(" Arg %2u: %s %s\n", i, typeName.c_str(), argName.c_str()); + if( typeQualifier != CL_KERNEL_ARG_TYPE_NONE ) { + logf( " TYPE_QUALIFIER: %s\n", + enumName().name_kernel_arg_type_qualifier( typeQualifier ).c_str() ); + } + if( accessQualifier != CL_KERNEL_ARG_ACCESS_NONE ) { + logf( " ACCESS_QUALIFIER: %s\n", + enumName().name( accessQualifier ).c_str() ); + } + if( addressQualifier != CL_KERNEL_ARG_ADDRESS_PRIVATE ) { + logf( " ADDRESS_QUALIFIER: %s\n", + enumName().name( addressQualifier ).c_str() ); + } + } + } } } } @@ -7899,14 +8027,13 @@ void CLIntercept::dumpCaptureReplayKernelInfo( std::ofstream outputArgTypes{dumpDirectory + "ArgumentDataTypes.txt"}; for( cl_uint idx = 0; idx != numArgs; ++idx ) { - size_t argTypeNameSize = 0; - dispatch().clGetKernelArgInfo(kernel, idx, CL_KERNEL_ARG_TYPE_NAME, 0, nullptr, &argTypeNameSize); - - std::string argTypeName(argTypeNameSize, ' '); - int error = dispatch().clGetKernelArgInfo(kernel, idx, CL_KERNEL_ARG_TYPE_NAME, argTypeNameSize, &argTypeName[0], nullptr); - if( error == CL_SUCCESS ) + std::string argTypeName; + if( getKernelArgInfoString( + kernel, + idx, + CL_KERNEL_ARG_TYPE_NAME, + argTypeName ) == CL_SUCCESS ) { - argTypeName.pop_back(); outputArgTypes << argTypeName << '\n'; } } diff --git a/intercept/src/intercept.h b/intercept/src/intercept.h index a35e2a66..b76b2f35 100644 --- a/intercept/src/intercept.h +++ b/intercept/src/intercept.h @@ -127,6 +127,11 @@ class CLIntercept cl_kernel kernel, cl_kernel_info param_name, std::string& str ) const; + cl_int getKernelArgInfoString( + cl_kernel kernel, + cl_uint arg_index, + cl_kernel_arg_info param_name, + std::string& str ) const; cl_int allocateAndGetProgramDeviceList( cl_program program, cl_uint& numDevices,