From ac828c9f34121ebedcb1f334d550eada7f56e6f1 Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Sat, 26 Oct 2024 14:31:31 -0700 Subject: [PATCH] add a control to find unique log and report file names Also, consistently use the spelling "file name" vs. "filename". --- docs/FAQ.md | 5 +- docs/controls.md | 32 ++++--- docs/injecting_programs.md | 10 +-- intercept/CMakeLists.txt | 2 + intercept/OS/OS_linux.h | 2 +- intercept/OS/OS_mac.h | 2 +- intercept/OS/OS_windows.h | 2 +- intercept/mdapi/intercept_mdapi.cpp | 7 +- intercept/scripts/run.py | 4 +- intercept/src/controls.h | 29 ++++--- intercept/src/intercept.cpp | 127 +++++++++++++++------------- intercept/src/intercept.h | 2 +- intercept/src/utils.cpp | 60 +++++++++++++ intercept/src/utils.h | 16 ++++ scripts/combine_chrome_traces.py | 10 +-- 15 files changed, 207 insertions(+), 103 deletions(-) create mode 100644 intercept/src/utils.cpp create mode 100644 intercept/src/utils.h diff --git a/docs/FAQ.md b/docs/FAQ.md index 69bdf076..4ab2e9ec 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -154,7 +154,10 @@ The most likely cause of this issue is an application that loads and unloads the When this occurs, the report file will only contain data collected between the last time the OpenCL Intercept Layer was loaded and unloaded, which could be no data at all. To determine if this issue is occurring, and to work around the issue if it is occurring, set the `AppendFiles` control. -`AppendFiles` causes logs and reports to append to an existing file instead of overwriting the file each time the OpenCL Intercept Layer is unloaded, preserving log or report data even when the OpenCL Intercept Layer is loaded and unloaded multiple times. +`AppendFiles` causes logs and reports to append to an existing file instead of overwriting the file each time the OpenCL Intercept Layer is loaded, preserving log or report data even when the OpenCL Intercept Layer is loaded and unloaded multiple times. + +For another option, set the `UniqueFiles` control. +`UniqueFiles` will find a unique file name for each log and report file instead of overwriting the file each time the OpenCL Intercept Layer is loaded. ## How can I debug or analyze multiple instances of an application? diff --git a/docs/controls.md b/docs/controls.md index 6b738b5c..94a8157b 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -255,6 +255,10 @@ If set, the Intercept Layer for OpenCL Applications will emit logs and dumps to If set, the Intercept Layer for OpenCL Applications will append process ID to the log directory name. +##### `UniqueFiles` (bool) + +If set, the Intercept Layer for OpenCL Applications will find a unique file name for logs and reports by appending a number to the file names, if needed. + ##### `KernelNameHashTracking` (bool) If set to a nonzero value, the Intercept Layer for OpenCL Applications will append the program and build option hashes to the kernel name in logs and reports. @@ -427,19 +431,19 @@ If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump ##### `DumpProgramSource` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every string passed to clCreateProgramWithSource() to its own file. The filename will have the form "CLI\_\\_\\_source.cl". Program options will be dumped to the same directory with the filename "CLI\_\\_\\_\\_\\_\\_options.txt", where API is an empty string for clBuildProgram(), "compile" for clCompileProgram(), and "link" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump programs for program injection. This setting overrides DumpProgramSourceScript and SimpleDumpProgramSource, and if it is set to a nozero value then the values of DumpProgramSourceScript and SimpleDumpProgramSource will be ignored. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every string passed to clCreateProgramWithSource() to its own file. The file name will have the form "CLI\_\\_\\_source.cl". Program options will be dumped to the same directory with the file name "CLI\_\\_\\_\\_\\_\\_options.txt", where API is an empty string for clBuildProgram(), "compile" for clCompileProgram(), and "link" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump programs for program injection. This setting overrides DumpProgramSourceScript and SimpleDumpProgramSource, and if it is set to a nozero value then the values of DumpProgramSourceScript and SimpleDumpProgramSource will be ignored. ##### `DumpInputProgramBinaries` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that is passed to clCreateProgramWithBinary() to its own file. The filename will have the form "CLI\_\\_\\_\.bin". This is the input program binary provided by the application, and not a device binary queried from the OpenCL implementation. In particular, note that it may be a SPIR 1.2 binary. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that is passed to clCreateProgramWithBinary() to its own file. The file name will have the form "CLI\_\\_\\_\.bin". This is the input program binary provided by the application, and not a device binary queried from the OpenCL implementation. In particular, note that it may be a SPIR 1.2 binary. ##### `DumpProgramBinaries` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that was successfully built with clBuildProgram() to its own file. The filename will have the form "CLI\_\\_\\_\\_\\_\.bin". Program options will be dumped to the same directory with the filename "CLI\_\\_\\_\\_\\_\\_options.txt", where API is an empty string for clBuildProgram(), "compile" for clCompileProgram(), and "link" for clLinkProgram(). This setting can be used to examine compiled program binaries or to dump program binaries for program binary injection. Note that this option dumps the output binary, which is a device binary, after calling clBuildProgram() or clLinkProgram(). +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that was successfully built with clBuildProgram() to its own file. The file name will have the form "CLI\_\\_\\_\\_\\_\.bin". Program options will be dumped to the same directory with the file name "CLI\_\\_\\_\\_\\_\\_options.txt", where API is an empty string for clBuildProgram(), "compile" for clCompileProgram(), and "link" for clLinkProgram(). This setting can be used to examine compiled program binaries or to dump program binaries for program binary injection. Note that this option dumps the output binary, which is a device binary, after calling clBuildProgram() or clLinkProgram(). ##### `DumpProgramSPIRV` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program IL binary passed to clCreateProgramWithIL() to its own file. The filename will have the form "CLI\_\\_\\_0000.spv" - for now at least!. Program options will be dumped to the same directory with the filename "CLI\_\\_\\_\\_\\_\\_options.txt", where \ is an empty string for clBuildProgram(), "compile" for clCompileProgram(), and "link" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump SPIRV programs for SPIRV injection. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program IL binary passed to clCreateProgramWithIL() to its own file. The file name will have the form "CLI\_\\_\\_0000.spv" - for now at least!. Program options will be dumped to the same directory with the file name "CLI\_\\_\\_\\_\\_\\_options.txt", where \ is an empty string for clBuildProgram(), "compile" for clCompileProgram(), and "link" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump SPIRV programs for SPIRV injection. ##### `InjectProgramSource` (bool) @@ -471,11 +475,11 @@ If set, the Intercept Layer for OpenCL Applications will add these build options ##### `DumpProgramBuildLogs` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump build logs for every device a program is built for to a separate file. The filename will have the form "CLI\_\\_\\_\\_\\_\\_build\_log.txt". +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump build logs for every device a program is built for to a separate file. The file name will have the form "CLI\_\\_\\_\\_\\_\\_build\_log.txt". ##### `DumpKernelISABinaries` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump kernel ISA binaries for every kernel, if supported. Currently, kernel ISA binaries are only supported for Intel GPU devices. Kernel ISA binaries can be decoded into ISA text with a disassembler. The filename will have the form "CLI\_\\_\\_\\_\\_\\_\.isabin". +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump kernel ISA binaries for every kernel, if supported. Currently, kernel ISA binaries are only supported for Intel GPU devices. Kernel ISA binaries can be decoded into ISA text with a disassembler. The file name will have the form "CLI\_\\_\\_\\_\\_\\_\.isabin". ### Controls for Emulating Features @@ -495,7 +499,7 @@ If set to a nonzero value, the Intercept Layer for OpenCL Applications will emul ##### `AutoCreateSPIRV` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will automatically create SPIR-V modules by invoking CLANG each time a program is built. The filename will have the form "CLI\_\\_\\_\\_\.spv". Because invoking CLANG requires a file containing the OpenCL C source, setting this option implicitly sets DumpProgramSource as well. Additionally, this feature is not available for injected program source. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will automatically create SPIR-V modules by invoking CLANG each time a program is built. The file name will have the form "CLI\_\\_\\_\\_\.spv". Because invoking CLANG requires a file containing the OpenCL C source, setting this option implicitly sets DumpProgramSource as well. Additionally, this feature is not available for injected program source. ##### `SPIRVClang` (string) @@ -529,7 +533,7 @@ If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump ##### `DumpArgumentsOnSet` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump the argument value on calls to clSetKernelArg(). Arguments are dumped as raw binary data. The filenames will have the form "SetKernelArg\_\\_Kernel\_\\_Arg\_\.bin". +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump the argument value on calls to clSetKernelArg(). Arguments are dumped as raw binary data. The file names will have the form "SetKernelArg\_\\_Kernel\_\\_Arg\_\.bin". ##### `DumpBuffersAfterCreate` (bool) @@ -545,11 +549,11 @@ If set, the Intercept Layer for OpenCL Applications will dump the contents of a ##### `DumpBuffersBeforeEnqueue` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a "memDumpPreEnqueue" subdirectory of the dump directory. The filenames will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Buffer\_\.bin". +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a "memDumpPreEnqueue" subdirectory of the dump directory. The file names will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Buffer\_\.bin". ##### `DumpBuffersAfterEnqueue` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments after calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a "memDumpPostEnqueue" subdirectory of the dump directory. The filenames will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Buffer\_\.bin". Note that this is the same naming convention as with DumpBuffersBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments after calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a "memDumpPostEnqueue" subdirectory of the dump directory. The file names will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Buffer\_\.bin". Note that this is the same naming convention as with DumpBuffersBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder. ##### `DumpBuffersForKernel` (string) @@ -557,11 +561,11 @@ If set, the Intercept Layer for OpenCL Applications will only dump buffer, SVM, ##### `DumpImagesBeforeEnqueue` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a "memDumpPreEnqueue" subdirectory of the dump directory. The filenames will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Image\_\\_\x\x\\_\bpp.raw". +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a "memDumpPreEnqueue" subdirectory of the dump directory. The file names will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Image\_\\_\x\x\\_\bpp.raw". ##### `DumpImagesAfterEnqueue` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments after calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a "memDumpPostEnqueue" subdirectory of the dump directory. The filenames will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Image\_\\_\x\x\\_\bpp.raw". Note that this is the same naming convention as with DumpImagesBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments after calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a "memDumpPostEnqueue" subdirectory of the dump directory. The file names will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Image\_\\_\x\x\\_\bpp.raw". Note that this is the same naming convention as with DumpImagesBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder. ##### `DumpImagesForKernel` (string) @@ -593,11 +597,11 @@ The Intercept Layer for OpenCL Applications will only dump kernel arguments when ##### `InjectBuffers` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified buffer, SVM, and USM contents before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued may be injected. The filename to inject will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Buffer\_\.bin", which matches the filename for dumped buffers. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified buffer, SVM, and USM contents before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued may be injected. The file name to inject will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Buffer\_\.bin", which matches the file name for dumped buffers. ##### `InjectImages` (bool) -If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified image contents before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued may be injected. The filename to inject will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Image\_\\_\x\x\\_\bpp.raw", which matches the filename for dumped images. +If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified image contents before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued may be injected. The file name to inject will have the form "Enqueue\_\\_Kernel\_\\_Arg\_\\_Image\_\\_\x\x\\_\bpp.raw", which matches the file name for dumped images. ### Device Partitioning Controls diff --git a/docs/injecting_programs.md b/docs/injecting_programs.md index fc9d5dbb..95f6910c 100644 --- a/docs/injecting_programs.md +++ b/docs/injecting_programs.md @@ -43,23 +43,23 @@ that this is a subdirectory of the dump directory. If the application compiles programs deterministically the program(s) or program options can be copied unchanged. If the application compiles programs non-deterministically, you may need rename the programs to modify to remove the -program number or compile count from the filename. +program number or compile count from the file name. The Intercept Layer for OpenCL Applications searches for program source filenames to inject in this order: -* `CLI___source.cl` - This is the default filename dumped +* `CLI___source.cl` - This is the default file name dumped by DumpProgramSource. -* `CLI__source.cl` - This is the default filename with the program number +* `CLI__source.cl` - This is the default file name with the program number removed, so the order the application calls clCreateProgramWithSource() does not matter. The Intercept Layer for OpenCL Applications searches for program option filenames to inject in this order: -* `CLI____options.txt` - This is the default filename +* `CLI____options.txt` - This is the default file name dumped by DumpProgramSource. -* `CLI___options.txt` - This is the default filename with the program +* `CLI___options.txt` - This is the default file name with the program number removed, so the order the application calls clCreateProgramWithSource() does not matter. * `CLI__options.txt` - This has both the program number and compile count diff --git a/intercept/CMakeLists.txt b/intercept/CMakeLists.txt index 3682e2d3..62c8c5f1 100644 --- a/intercept/CMakeLists.txt +++ b/intercept/CMakeLists.txt @@ -79,6 +79,8 @@ set(CLINTERCEPT_SOURCE_FILES src/main.cpp src/objtracker.cpp src/objtracker.h + src/utils.cpp + src/utils.h "${CMAKE_CURRENT_BINARY_DIR}/git_version.cpp" ) source_group(Source FILES diff --git a/intercept/OS/OS_linux.h b/intercept/OS/OS_linux.h index 1d4ea86d..da2cc6b2 100644 --- a/intercept/OS/OS_linux.h +++ b/intercept/OS/OS_linux.h @@ -42,7 +42,7 @@ class Services : public Services_Common size_t& length ) const; bool ExecuteCommand( - const std::string& filename ) const; + const std::string& fileName ) const; bool StartAubCapture( const std::string& fileName, uint64_t delay ) const; diff --git a/intercept/OS/OS_mac.h b/intercept/OS/OS_mac.h index 5d7774f6..88439b0a 100644 --- a/intercept/OS/OS_mac.h +++ b/intercept/OS/OS_mac.h @@ -36,7 +36,7 @@ class Services : public Services_Common size_t& length ) const; bool ExecuteCommand( - const std::string& filename ) const; + const std::string& fileName ) const; bool StartAubCapture( const std::string& fileName, uint64_t delay ) const; diff --git a/intercept/OS/OS_windows.h b/intercept/OS/OS_windows.h index 4ec67e8f..57fe5e63 100644 --- a/intercept/OS/OS_windows.h +++ b/intercept/OS/OS_windows.h @@ -37,7 +37,7 @@ class Services : public Services_Common size_t& length ) const; bool ExecuteCommand( - const std::string& filename ) const; + const std::string& fileName ) const; bool StartAubCapture( const std::string& fileName, uint64_t delay ) const; diff --git a/intercept/mdapi/intercept_mdapi.cpp b/intercept/mdapi/intercept_mdapi.cpp index f5b6063b..2b9c4c6f 100644 --- a/intercept/mdapi/intercept_mdapi.cpp +++ b/intercept/mdapi/intercept_mdapi.cpp @@ -9,6 +9,7 @@ #include "common.h" #include "intercept.h" +#include "utils.h" #define CL_PROFILING_COMMAND_PERFCOUNTERS_INTEL 0x407F @@ -202,12 +203,16 @@ void CLIntercept::initCustomPerfCounters() std::string fileName = ""; OS().GetDumpDirectoryName( sc_DumpDirectoryName, fileName ); fileName += '/'; - fileName += sc_DumpPerfCountersFileNamePrefix; + fileName += sc_PerfCountersFileNamePrefix; fileName += "_"; fileName += metricSetSymbolName; fileName += ".csv"; OS().MakeDumpDirectories( fileName ); + if( m_Config.UniqueFiles ) + { + fileName = Utils::GetUniqueFileName(fileName); + } m_MetricDump.open( fileName.c_str(), std::ios::out | std::ios::binary ); diff --git a/intercept/scripts/run.py b/intercept/scripts/run.py index 9e21c3b1..c38a3351 100644 --- a/intercept/scripts/run.py +++ b/intercept/scripts/run.py @@ -15,8 +15,8 @@ from collections import defaultdict def get_image_metadata(idx: int): - filename = f"./Image_MetaData_{idx}.txt" - with open(filename) as metadata: + fileName = f"./Image_MetaData_{idx}.txt" + with open(fileName) as metadata: lines = metadata.readlines() image_type = int(lines[8]) diff --git a/intercept/src/controls.h b/intercept/src/controls.h index 969e50d8..6bc903a8 100644 --- a/intercept/src/controls.h +++ b/intercept/src/controls.h @@ -44,6 +44,7 @@ CLI_CONTROL( bool, CLInfoLogging, false, "If s CLI_CONTROL( bool, FlushFiles, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will flush files after ever write. This slows down performance but can help to avoid truncated files if the Intercept Layer for OpenCL Applications does not exit cleanly." ) CLI_CONTROL( std::string, DumpDir, "", "If set, the Intercept Layer for OpenCL Applications will emit logs and dumps to this directory instead of the default directory. The default log and dump directory is \"%SYSTEMDRIVE%\\Intel\\CLIntercept_Dump\\\" on Windows and \"~/CLIntercept_Dump/\" on other operating systems. The log and dump directory must be writeable, otherwise the Intercept Layer for OpenCL Applications will not be able to create or modify log or dump files." ) CLI_CONTROL( bool, AppendPid, false, "If set, the Intercept Layer for OpenCL Applications will append process ID to the log directory name." ) +CLI_CONTROL( bool, UniqueFiles, false, "If set, the Intercept Layer for OpenCL Applications will find a unique file name for logs and reports by appending a number to the file names, if needed." ) CLI_CONTROL( bool, KernelNameHashTracking, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will append the program and build option hashes to the kernel name in logs and reports." ) CLI_CONTROL( cl_uint, LongKernelNameCutoff, UINT_MAX, "If an OpenCL application uses kernels with very long names, the Intercept Layer for OpenCL Applications can substitute a \"short\" kernel identifier for a \"long\" kernel name in logs and reports. This control defines how long a kernel name must be (in characters) before it is replaced by a \"short\" kernel identifier." ) CLI_CONTROL( bool, DemangleKernelNames, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will track kernel names that are demangled according to C++ ABI rules. This setting requires compiler support for demangling and may not be available in all configurations." ) @@ -91,10 +92,10 @@ CLI_CONTROL_SEPARATOR( Controls for Dumping and Injecting Programs and Build Opt CLI_CONTROL( bool, OmitProgramNumber, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will omit the program number from dumped file names and hash tracking. This can produce deterministic results even if programs are built in a non-deterministic order (say, by multiple threads)." ) CLI_CONTROL( bool, SimpleDumpProgramSource, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump the last string(s) passed to clCreateProgramWithSource() to the file kernel.cl, and the last program options passed to clBuildProgram() to the file kernel.txt. These files will be dumped to the application's working directory. If an application fails to compile a program and exits the program immediately after detecting a compile failure SimpleDumpProgram may be all that is needed to identify the program and program options that are failing to compile." ) CLI_CONTROL( bool, DumpProgramSourceScript, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every string passed to clCreateProgramWithSource() to its own file. The directory names and file names for the dumped files match the directory names and file names expected by a modified OpenCL conformance test script to capture kernels. This setting overrides SimpleDumpProgramSource, and if it is set to a nonzero value then the value of SimpleDumpProgramSource is ignored." ) -CLI_CONTROL( bool, DumpProgramSource, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every string passed to clCreateProgramWithSource() to its own file. The filename will have the form \"CLI___source.cl\". Program options will be dumped to the same directory with the filename \"CLI______options.txt\", where API is an empty string for clBuildProgram(), \"compile\" for clCompileProgram(), and \"link\" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump programs for program injection. This setting overrides DumpProgramSourceScript and SimpleDumpProgramSource, and if it is set to a nozero value then the values of DumpProgramSourceScript and SimpleDumpProgramSource will be ignored." ) -CLI_CONTROL( bool, DumpInputProgramBinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that is passed to clCreateProgramWithBinary() to its own file. The filename will have the form \"CLI___.bin\". This is the input program binary provided by the application, and not a device binary queried from the OpenCL implementation. In particular, note that it may be a SPIR 1.2 binary." ) -CLI_CONTROL( bool, DumpProgramBinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that was successfully built with clBuildProgram() to its own file. The filename will have the form \"CLI_____.bin\". Program options will be dumped to the same directory with the filename \"CLI______options.txt\", where API is an empty string for clBuildProgram(), \"compile\" for clCompileProgram(), and \"link\" for clLinkProgram(). This setting can be used to examine compiled program binaries or to dump program binaries for program binary injection. Note that this option dumps the output binary, which is a device binary, after calling clBuildProgram() or clLinkProgram()." ) -CLI_CONTROL( bool, DumpProgramSPIRV, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program IL binary passed to clCreateProgramWithIL() to its own file. The filename will have the form \"CLI___0000.spv\" - for now at least!. Program options will be dumped to the same directory with the filename \"CLI______options.txt\", where is an empty string for clBuildProgram(), \"compile\" for clCompileProgram(), and \"link\" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump SPIRV programs for SPIRV injection." ) +CLI_CONTROL( bool, DumpProgramSource, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every string passed to clCreateProgramWithSource() to its own file. The file name will have the form \"CLI___source.cl\". Program options will be dumped to the same directory with the file name \"CLI______options.txt\", where API is an empty string for clBuildProgram(), \"compile\" for clCompileProgram(), and \"link\" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump programs for program injection. This setting overrides DumpProgramSourceScript and SimpleDumpProgramSource, and if it is set to a nozero value then the values of DumpProgramSourceScript and SimpleDumpProgramSource will be ignored." ) +CLI_CONTROL( bool, DumpInputProgramBinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that is passed to clCreateProgramWithBinary() to its own file. The file name will have the form \"CLI___.bin\". This is the input program binary provided by the application, and not a device binary queried from the OpenCL implementation. In particular, note that it may be a SPIR 1.2 binary." ) +CLI_CONTROL( bool, DumpProgramBinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program binary that was successfully built with clBuildProgram() to its own file. The file name will have the form \"CLI_____.bin\". Program options will be dumped to the same directory with the file name \"CLI______options.txt\", where API is an empty string for clBuildProgram(), \"compile\" for clCompileProgram(), and \"link\" for clLinkProgram(). This setting can be used to examine compiled program binaries or to dump program binaries for program binary injection. Note that this option dumps the output binary, which is a device binary, after calling clBuildProgram() or clLinkProgram()." ) +CLI_CONTROL( bool, DumpProgramSPIRV, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump every program IL binary passed to clCreateProgramWithIL() to its own file. The file name will have the form \"CLI___0000.spv\" - for now at least!. Program options will be dumped to the same directory with the file name \"CLI______options.txt\", where is an empty string for clBuildProgram(), \"compile\" for clCompileProgram(), and \"link\" for clLinkProgram(). This setting can be used for information purposes to see all kernels that are used by an application or to dump SPIRV programs for SPIRV injection." ) CLI_CONTROL( bool, InjectProgramSource, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified kernel source to clCreateProgramWithSource() and/or potentially modified options to clCompileProgram() or clBuildProgram(). Note that program options currently cannot be injected for clLinkProgram()." ) CLI_CONTROL( bool, InjectProgramBinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified kernel binaries via clCreateProgramWithBinary() in place of program text for each call to clCreateProgramWithSource(). This is typically done to reduce program compilation time or to use known good program binaries." ) CLI_CONTROL( bool, RejectProgramBinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will reject kernel binaries passed via clCreateProgramWithBinary() and return CL_INVALID_BINARY. This can be used to force an application to re-compile program binaries from source." ) @@ -102,8 +103,8 @@ CLI_CONTROL( bool, InjectProgramSPIRV, false, "If s CLI_CONTROL( bool, PrependProgramSource, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to prepend kernel code from a file to the application provided kernel source passed to clCreateProgramWithSource(). The Intercept Layer for OpenCL Applications will look for kernel source to prepend in the dump and log directory. The files that are searched for are (in order) \"CLI___prepend.cl\", \"CLI__prepend.cl\", and \"CLI_prepend.cl\"." ) CLI_CONTROL( std::string, AppendBuildOptions, "", "If set, the Intercept Layer for OpenCL Applications will add these build options to the end of any application provided or injected build options for each call to clCompileProgram or clBuildProgram()." ) CLI_CONTROL( std::string, AppendLinkOptions, "", "If set, the Intercept Layer for OpenCL Applications will add these build options to the end of any application provided or injected build options for each call to clLinkProgram()." ) -CLI_CONTROL( bool, DumpProgramBuildLogs, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump build logs for every device a program is built for to a separate file. The filename will have the form \"CLI______build_log.txt\"." ) -CLI_CONTROL( bool, DumpKernelISABinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump kernel ISA binaries for every kernel, if supported. Currently, kernel ISA binaries are only supported for Intel GPU devices. Kernel ISA binaries can be decoded into ISA text with a disassembler. The filename will have the form \"CLI______.isabin\"." ) +CLI_CONTROL( bool, DumpProgramBuildLogs, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump build logs for every device a program is built for to a separate file. The file name will have the form \"CLI______build_log.txt\"." ) +CLI_CONTROL( bool, DumpKernelISABinaries, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump kernel ISA binaries for every kernel, if supported. Currently, kernel ISA binaries are only supported for Intel GPU devices. Kernel ISA binaries can be decoded into ISA text with a disassembler. The file name will have the form \"CLI______.isabin\"." ) CLI_CONTROL_SEPARATOR( Controls for Emulating Features: ) CLI_CONTROL( bool, Emulate_cl_khr_extended_versioning, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will emulate support for the cl_khr_extended_versioning extension." ) @@ -111,7 +112,7 @@ CLI_CONTROL( bool, Emulate_cl_khr_semaphore, false, "If s CLI_CONTROL( bool, Emulate_cl_intel_unified_shared_memory, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will emulate support for the cl_intel_unified_shared_memory extension USM APIs using SVM APIs. This can be useful to test USM applications on an implementation that supports SVM, but not USM." ) CLI_CONTROL_SEPARATOR( Controls for Automatically Creating SPIR-V Modules: ) -CLI_CONTROL( bool, AutoCreateSPIRV, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will automatically create SPIR-V modules by invoking CLANG each time a program is built. The filename will have the form \"CLI____.spv\". Because invoking CLANG requires a file containing the OpenCL C source, setting this option implicitly sets DumpProgramSource as well. Additionally, this feature is not available for injected program source." ) +CLI_CONTROL( bool, AutoCreateSPIRV, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will automatically create SPIR-V modules by invoking CLANG each time a program is built. The file name will have the form \"CLI____.spv\". Because invoking CLANG requires a file containing the OpenCL C source, setting this option implicitly sets DumpProgramSource as well. Additionally, this feature is not available for injected program source." ) CLI_CONTROL( std::string, SPIRVClang, "clang", "The clang executable used to compile an OpenCL C program to a SPIR-V module. This can be an executable in the system path, a relative path, or a full absolute path." ) CLI_CONTROL( std::string, SPIRVCLHeader, "opencl.h", "The OpenCL header file used to compile an OpenCL C program to a SPIR-V module. This must be a relative path or a full absolute path." ) CLI_CONTROL( std::string, SPIRVDis, "spirv-dis", "The spirv-dis executable used to optionally disassemble the compiled SPIR-V module to a SPIR-V text representation. This can be an executable in the system path, a relative path, or a full absolute path." ) @@ -121,15 +122,15 @@ CLI_CONTROL( std::string, OpenCL2Options, "-cc1 -x cl CLI_CONTROL_SEPARATOR( Controls for Dumping and Injecting Buffers and Images: ) CLI_CONTROL( bool, DumpBufferHashes, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump hashes of a buffer, SVM, or USM allocation rather than the full contents of the buffer. This can be useful to identify which kernel enqueues generate different results without requiring a large amount of disk space." ) CLI_CONTROL( bool, DumpImageHashes, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump hashes of an image rather than the full contents of the image. This can be useful to identify which kernel enqueues generate different results without requiring a large amount of disk space." ) -CLI_CONTROL( bool, DumpArgumentsOnSet, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump the argument value on calls to clSetKernelArg(). Arguments are dumped as raw binary data. The filenames will have the form \"SetKernelArg__Kernel__Arg_.bin\"." ) +CLI_CONTROL( bool, DumpArgumentsOnSet, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump the argument value on calls to clSetKernelArg(). Arguments are dumped as raw binary data. The file names will have the form \"SetKernelArg__Kernel__Arg_.bin\"." ) CLI_CONTROL( bool, DumpBuffersAfterCreate, false, "If set, the Intercept Layer for OpenCL Applications will dump buffers to a file after creation. This control still honors the enqueue counter limits, even though no enqueues are involved during buffer creation. Currently only works for cl_mem buffers created from host pointers." ) CLI_CONTROL( bool, DumpBuffersAfterMap, false, "If set, the Intercept Layer for OpenCL Applications will dump the contents of a buffer to a file after the buffer is mapped. Only valid if the buffer is NOT mapped with CL_MAP_WRITE_INVALIDATE_REGION. If the buffer was mapped non-blocking, this may insert a clFinish() into the command queue, which may have functional or performance implications." ) CLI_CONTROL( bool, DumpBuffersBeforeUnmap, false, "If set, the Intercept Layer for OpenCL Applications will dump the contents of a buffer to a file immediately before the buffer is unmapped. This is done by inserting a blocking clEnqueueMapBuffer() (and matching clEnqueueUnmapMemObject()) into the command queue, which may have functional or performance implications." ) -CLI_CONTROL( bool, DumpBuffersBeforeEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a \"memDumpPreEnqueue\" subdirectory of the dump directory. The filenames will have the form \"Enqueue__Kernel__Arg__Buffer_.bin\"." ) -CLI_CONTROL( bool, DumpBuffersAfterEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments after calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a \"memDumpPostEnqueue\" subdirectory of the dump directory. The filenames will have the form \"Enqueue__Kernel__Arg__Buffer_.bin\". Note that this is the same naming convention as with DumpBuffersBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder." ) +CLI_CONTROL( bool, DumpBuffersBeforeEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a \"memDumpPreEnqueue\" subdirectory of the dump directory. The file names will have the form \"Enqueue__Kernel__Arg__Buffer_.bin\"." ) +CLI_CONTROL( bool, DumpBuffersAfterEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump buffer, SVM, and USM kernel arguments after calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued are dumped. Buffers are dumped as raw binary data to a \"memDumpPostEnqueue\" subdirectory of the dump directory. The file names will have the form \"Enqueue__Kernel__Arg__Buffer_.bin\". Note that this is the same naming convention as with DumpBuffersBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder." ) CLI_CONTROL( std::string, DumpBuffersForKernel, "", "If set, the Intercept Layer for OpenCL Applications will only dump buffer, SVM, and USM kernel arguments when the specified kernel is enqueued. This control is ignored unless DumpBuffersBeforeEnqueue or DumpBuffersAfterEnqueue are enabled." ) -CLI_CONTROL( bool, DumpImagesBeforeEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a \"memDumpPreEnqueue\" subdirectory of the dump directory. The filenames will have the form \"Enqueue__Kernel__Arg__Image__xx_bpp.raw\"." ) -CLI_CONTROL( bool, DumpImagesAfterEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments after calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a \"memDumpPostEnqueue\" subdirectory of the dump directory. The filenames will have the form \"Enqueue__Kernel__Arg__Image__xx_bpp.raw\". Note that this is the same naming convention as with DumpImagesBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder." ) +CLI_CONTROL( bool, DumpImagesBeforeEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a \"memDumpPreEnqueue\" subdirectory of the dump directory. The file names will have the form \"Enqueue__Kernel__Arg__Image__xx_bpp.raw\"." ) +CLI_CONTROL( bool, DumpImagesAfterEnqueue, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will dump image kernel arguments after calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued are dumped. Images are dumped as raw binary data to a \"memDumpPostEnqueue\" subdirectory of the dump directory. The file names will have the form \"Enqueue__Kernel__Arg__Image__xx_bpp.raw\". Note that this is the same naming convention as with DumpImagesBeforeEnqueue, so the changes resulting from an enqueue can be determined by diff'ing the preEnqueue folder with the postEnqueue folder." ) CLI_CONTROL( std::string, DumpImagesForKernel, "", "If set, the Intercept Layer for OpenCL Applications will only dump image kernel arguments when the specified kernel is enqueued. This control is ignored unless DumpImagesBeforeEnqueue or DumpImagesAfterEnqueue are enabled." ) CLI_CONTROL( cl_uint, DumpBuffersMinEnqueue, 0, "The Intercept Layer for OpenCL Applications will only dump buffer, SVM, and USM kernel arguments when the enqueue counter is greater than this value, inclusive." ) CLI_CONTROL( cl_uint, DumpBuffersMaxEnqueue, UINT_MAX, "The Intercept Layer for OpenCL Applications will only dump buffer, SVM, and USM kernel arguments when the enqueue counter is less than this value, inclusive." ) @@ -137,8 +138,8 @@ CLI_CONTROL( cl_uint, DumpImagesMinEnqueue, 0, "The CLI_CONTROL( cl_uint, DumpImagesMaxEnqueue, UINT_MAX, "The Intercept Layer for OpenCL Applications will only dump image kernel arguments when the enqueue counter is less than this value, inclusive." ) CLI_CONTROL( cl_uint, DumpArgumentsOnSetMinEnqueue, 0, "The Intercept Layer for OpenCL Applications will only dump argument values when the enqueue counter is greater than this value, inclusive." ) CLI_CONTROL( cl_uint, DumpArgumentsOnSetMaxEnqueue, UINT_MAX, "The Intercept Layer for OpenCL Applications will only dump kernel arguments when the enqueue counter is less than this value, inclusive." ) -CLI_CONTROL( bool, InjectBuffers, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified buffer, SVM, and USM contents before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued may be injected. The filename to inject will have the form \"Enqueue__Kernel__Arg__Buffer_.bin\", which matches the filename for dumped buffers." ) -CLI_CONTROL( bool, InjectImages, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified image contents before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued may be injected. The filename to inject will have the form \"Enqueue__Kernel__Arg__Image__xx_bpp.raw\", which matches the filename for dumped images." ) +CLI_CONTROL( bool, InjectBuffers, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified buffer, SVM, and USM contents before calls to clEnqueueNDRangeKernel(). Only buffers that are kernel arguments for the kernel being enqueued may be injected. The file name to inject will have the form \"Enqueue__Kernel__Arg__Buffer_.bin\", which matches the file name for dumped buffers." ) +CLI_CONTROL( bool, InjectImages, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will look to inject potentially modified image contents before calls to clEnqueueNDRangeKernel(). Only images that are kernel arguments for the kernel being enqueued may be injected. The file name to inject will have the form \"Enqueue__Kernel__Arg__Image__xx_bpp.raw\", which matches the file name for dumped images." ) CLI_CONTROL_SEPARATOR( Device Partitioning Controls: ) CLI_CONTROL( bool, AutoPartitionAllDevices, false, "If set to a nonzero value, the Intercept Layer for OpenCL Applications will automatically partition parent devices and return all parent devices and all sub-devices." ) diff --git a/intercept/src/intercept.cpp b/intercept/src/intercept.cpp index a05489f2..58f4fc78 100644 --- a/intercept/src/intercept.cpp +++ b/intercept/src/intercept.cpp @@ -17,6 +17,7 @@ #include "demangle.h" #include "emulate.h" #include "intercept.h" +#include "utils.h" /*****************************************************************************\ @@ -90,7 +91,7 @@ const char* CLIntercept::sc_URL = "https://github.com/intel/opencl-intercept-lay const char* CLIntercept::sc_DumpDirectoryName = "CLIntercept_Dump"; const char* CLIntercept::sc_ReportFileName = "clintercept_report.txt"; const char* CLIntercept::sc_LogFileName = "clintercept_log.txt"; -const char* CLIntercept::sc_DumpPerfCountersFileNamePrefix = "clintercept_perfcounter"; +const char* CLIntercept::sc_PerfCountersFileNamePrefix = "clintercept_perfcounter"; const char* CLIntercept::sc_TraceFileName = "clintercept_trace.json"; /////////////////////////////////////////////////////////////////////////////// @@ -411,6 +412,10 @@ bool CLIntercept::init() fileName += sc_LogFileName; OS().MakeDumpDirectories( fileName ); + if( m_Config.UniqueFiles ) + { + fileName = Utils::GetUniqueFileName(fileName); + } if( m_Config.AppendFiles ) { @@ -436,6 +441,10 @@ bool CLIntercept::init() fileName += sc_TraceFileName; OS().MakeDumpDirectories( fileName ); + if( m_Config.UniqueFiles ) + { + fileName = Utils::GetUniqueFileName(fileName); + } uint64_t processId = OS().GetProcessID(); uint32_t bufferSize = m_Config.ChromeTraceBufferSize; @@ -655,13 +664,13 @@ void CLIntercept::report() { std::lock_guard lock(m_Mutex); - char filepath[MAX_PATH] = ""; + char filePath[MAX_PATH] = ""; #if defined(_WIN32) if( config().DumpProgramSourceScript ) { - char dirname[MAX_PATH] = ""; - char filename[MAX_PATH] = ""; + char dirName[MAX_PATH] = ""; + char fileName[MAX_PATH] = ""; size_t remaining = MAX_PATH; @@ -673,7 +682,7 @@ void CLIntercept::report() // Directory: - curPos = dirname; + curPos = dirName; remaining = MAX_PATH; memset( curPos, 0, MAX_PATH ); @@ -696,21 +705,21 @@ void CLIntercept::report() curPos += 2; remaining -= 2; - ::CreateDirectoryA( dirname, NULL ); + ::CreateDirectoryA( dirName, NULL ); // File: - curPos = filename; + curPos = fileName; remaining = MAX_PATH; memset( curPos, 0, MAX_PATH ); - if( GetModuleFileNameA( NULL, filename, MAX_PATH-1 ) == 0 ) + if( GetModuleFileNameA( NULL, fileName, MAX_PATH-1 ) == 0 ) { CLI_ASSERT( 0 ); strcpy_s( curPos, remaining, "process.exe" ); } - pch = strrchr( filename, '\\' ); + pch = strrchr( fileName, '\\' ); pch++; memcpy_s( curPos, remaining, pch, strlen( pch ) ); curPos += strlen( pch ) - 4; // -4 to cut off ".exe" @@ -736,7 +745,7 @@ void CLIntercept::report() curPos += 1; remaining -= 1; - CLI_SPRINTF( filepath, MAX_PATH, "%s/%s.%s", dirname, filename, "log" ); + CLI_SPRINTF( filePath, MAX_PATH, "%s/%s.%s", dirName, fileName, "log" ); } else #endif @@ -748,8 +757,12 @@ void CLIntercept::report() fileName += sc_ReportFileName; OS().MakeDumpDirectories( fileName ); + if( m_Config.UniqueFiles ) + { + fileName = Utils::GetUniqueFileName(fileName); + } - CLI_SPRINTF( filepath, MAX_PATH, "%s", fileName.c_str() ); + CLI_SPRINTF( filePath, MAX_PATH, "%s", fileName.c_str() ); } // Report @@ -765,13 +778,13 @@ void CLIntercept::report() if( m_Config.AppendFiles ) { os.open( - filepath, + filePath, std::ios::out | std::ios::binary | std::ios::app ); } else { os.open( - filepath, + filePath, std::ios::out | std::ios::binary ); } if( os.good() ) @@ -781,7 +794,7 @@ void CLIntercept::report() } else { - logf( "Failed to open report file for writing: %s\n", filepath ); + logf( "Failed to open report file for writing: %s\n", filePath ); } } } @@ -4185,7 +4198,7 @@ bool CLIntercept::injectProgramSource( fileName += "/Inject"; } - // Make two candidate filenames. They will have the form: + // Make two candidate file names. They will have the form: // CLI___source.cl, or // CLI__source.cl { @@ -4295,7 +4308,7 @@ bool CLIntercept::prependProgramSource( fileName += "/Inject"; } - // Make three candidate filenames. They will have the form: + // Make three candidate file names. They will have the form: // CLI___prepend.cl, or // CLI__prepend.cl, or // CLI_prepend.cl @@ -4425,7 +4438,7 @@ bool CLIntercept::injectProgramSPIRV( fileName += "/Inject"; } - // Make two candidate filenames. They will have the form: + // Make two candidate file names. They will have the form: // CLI___0000.spv, or // CLI__0000.spv { @@ -4527,7 +4540,7 @@ bool CLIntercept::injectProgramOptions( OS().GetDumpDirectoryNameWithoutPid( sc_DumpDirectoryName, fileName ); fileName += "/Inject"; } - // Make four candidate filenames. They will have the form: + // Make four candidate file names. They will have the form: // CLI_____options.txt, or // CLI____options.txt, or // CLI__options.txt, or @@ -4718,9 +4731,9 @@ void CLIntercept::dumpProgramSourceScript( CLI_ASSERT( config().DumpProgramSourceScript || config().SimpleDumpProgramSource ); - char dirname[MAX_PATH] = ""; - char filename[MAX_PATH] = ""; - char filepath[MAX_PATH] = ""; + char dirName[MAX_PATH] = ""; + char fileName[MAX_PATH] = ""; + char filePath[MAX_PATH] = ""; if( config().DumpProgramSourceScript ) { @@ -4734,7 +4747,7 @@ void CLIntercept::dumpProgramSourceScript( // Directory: - curPos = dirname; + curPos = dirName; remaining = MAX_PATH; memset( curPos, 0, MAX_PATH ); @@ -4757,21 +4770,21 @@ void CLIntercept::dumpProgramSourceScript( curPos += 2; remaining -= 2; - ::CreateDirectoryA( dirname, NULL ); + ::CreateDirectoryA( dirName, NULL ); // File: - curPos = filename; + curPos = fileName; remaining = MAX_PATH; memset( curPos, 0, MAX_PATH ); - if( GetModuleFileNameA( NULL, filename, MAX_PATH-1 ) == 0 ) + if( GetModuleFileNameA( NULL, fileName, MAX_PATH-1 ) == 0 ) { CLI_ASSERT( 0 ); strcpy_s( curPos, remaining, "process.exe" ); } - pch = strrchr( filename, '\\' ); + pch = strrchr( fileName, '\\' ); pch++; memcpy_s( curPos, remaining, pch, strlen( pch ) ); curPos += strlen( pch ) - 4; // -4 to cut off ".exe" @@ -4799,16 +4812,16 @@ void CLIntercept::dumpProgramSourceScript( } else { - CLI_SPRINTF( dirname, MAX_PATH, "." ); - CLI_SPRINTF( filename, MAX_PATH, "kernel" ); + CLI_SPRINTF( dirName, MAX_PATH, "." ); + CLI_SPRINTF( fileName, MAX_PATH, "kernel" ); } - CLI_SPRINTF( filepath, MAX_PATH, "%s/%s.%s", dirname, filename, "cl" ); + CLI_SPRINTF( filePath, MAX_PATH, "%s/%s.%s", dirName, fileName, "cl" ); if( singleString ) { dumpMemoryToFile( - filepath, + filePath, false, singleString, strlen(singleString) ); @@ -4848,7 +4861,7 @@ void CLIntercept::dumpProgramSource( fileName += "/Modified"; } - // Make the filename. It will have the form: + // Make the file name. It will have the form: // CLI___source.cl { char numberString[256] = ""; @@ -4917,7 +4930,7 @@ void CLIntercept::dumpInputProgramBinaries( fileName += "/Modified"; } - // Make the filename. It will have the form: + // Make the file name. It will have the form: // CLI__ // Leave off the extension for now. { @@ -5017,7 +5030,7 @@ void CLIntercept::dumpProgramSPIRV( fileName += "/Modified"; } - // Make the filename. It will have the form: + // Make the file name. It will have the form: // CLI___0000.spv { char numberString[256] = ""; @@ -5089,9 +5102,9 @@ void CLIntercept::dumpProgramOptionsScript( if( options ) { - char dirname[MAX_PATH] = ""; - char filename[MAX_PATH] = ""; - char filepath[MAX_PATH] = ""; + char dirName[MAX_PATH] = ""; + char fileName[MAX_PATH] = ""; + char filePath[MAX_PATH] = ""; if( config().DumpProgramSourceScript ) { @@ -5105,7 +5118,7 @@ void CLIntercept::dumpProgramOptionsScript( // Directory: - curPos = dirname; + curPos = dirName; remaining = MAX_PATH; memset( curPos, 0, MAX_PATH ); @@ -5128,21 +5141,21 @@ void CLIntercept::dumpProgramOptionsScript( curPos += 2; remaining -= 2; - ::CreateDirectoryA( dirname, NULL ); + ::CreateDirectoryA( dirName, NULL ); // File: - curPos = filename; + curPos = fileName; remaining = MAX_PATH; memset( curPos, 0, MAX_PATH ); - if( GetModuleFileNameA( NULL, filename, MAX_PATH-1 ) == 0 ) + if( GetModuleFileNameA( NULL, fileName, MAX_PATH-1 ) == 0 ) { CLI_ASSERT( 0 ); strcpy_s( curPos, remaining, "process.exe" ); } - pch = strrchr( filename, '\\' ); + pch = strrchr( fileName, '\\' ); pch++; memcpy_s( curPos, remaining, pch, strlen( pch ) ); curPos += strlen( pch ) - 4; // -4 to cut off ".exe" @@ -5170,14 +5183,14 @@ void CLIntercept::dumpProgramOptionsScript( } else { - CLI_SPRINTF( dirname, MAX_PATH, "." ); - CLI_SPRINTF( filename, MAX_PATH, "kernel" ); + CLI_SPRINTF( dirName, MAX_PATH, "." ); + CLI_SPRINTF( fileName, MAX_PATH, "kernel" ); } - CLI_SPRINTF( filepath, MAX_PATH, "%s/%s.%s", dirname, filename, "txt" ); + CLI_SPRINTF( filePath, MAX_PATH, "%s/%s.%s", dirName, fileName, "txt" ); dumpMemoryToFile( - filepath, + filePath, false, options, strlen(options) ); @@ -5220,7 +5233,7 @@ void CLIntercept::dumpProgramOptions( fileName += "/Modified"; } - // Make the filename. It will have the form: + // Make the file name. It will have the form: // CLI____ // Leave off the extension for now. { @@ -5289,7 +5302,7 @@ void CLIntercept::dumpProgramBuildLog( { OS().GetDumpDirectoryName( sc_DumpDirectoryName, fileName ); } - // Make the filename. It will have the form: + // Make the file name. It will have the form: // CLI____ // Leave off the extension for now. { @@ -7745,7 +7758,7 @@ void CLIntercept::dumpBuffersForKernel( fileName += tmpStr; } - // Add the kernel name to the filename + // Add the kernel name to the file name { fileName += "_Kernel_"; fileName += getShortKernelName(kernel); @@ -7986,7 +7999,7 @@ void CLIntercept::dumpImagesForKernel( fileName += tmpStr; } - // Add the kernel name to the filename + // Add the kernel name to the file name { fileName += "_Kernel_"; fileName += getShortKernelName(kernel); @@ -8124,7 +8137,7 @@ void CLIntercept::injectBuffersForKernel( fileName += tmpStr; } - // Add the kernel name to the filename + // Add the kernel name to the file name { fileName += "_Kernel_"; fileName += getShortKernelName(kernel); @@ -8317,7 +8330,7 @@ void CLIntercept::injectImagesForKernel( fileName += tmpStr; } - // Add the kernel name to the filename + // Add the kernel name to the file name { fileName += "_Kernel_"; fileName += getShortKernelName(kernel); @@ -8441,7 +8454,7 @@ void CLIntercept::dumpArgument( fileName += enqueueCount; } - // Add the kernel name to the filename + // Add the kernel name to the file name { fileName += "_Kernel_"; fileName += getShortKernelName(kernel); @@ -9260,7 +9273,7 @@ void CLIntercept::startAubCapture( fileName, config().AubCaptureStartWait ); } - log( "AubCapture started... maybe. Filename is: " + fileName + "\n" ); + log( "AubCapture started... maybe. File name is: " + fileName + "\n" ); // No matter what, set the flag that aubcapture is started, so we // don't try again. @@ -9716,7 +9729,7 @@ cl_program CLIntercept::createProgramWithInjectionBinaries( OS().GetDumpDirectoryNameWithoutPid( sc_DumpDirectoryName, fileName ); fileName += "/Inject"; } - // Make two candidate filenames. They will have the form: + // Make two candidate file names. They will have the form: // CLI___0000, or // CLI__0000 // Leave off the extension for now. @@ -9943,7 +9956,7 @@ void CLIntercept::dumpProgramBinary( { OS().GetDumpDirectoryName( sc_DumpDirectoryName, fileName ); } - // Make the filename. It will have the form: + // Make the file name. It will have the form: // CLI____ // Leave off the extension for now. { @@ -10183,7 +10196,7 @@ void CLIntercept::dumpKernelISABinaries( { OS().GetDumpDirectoryName( sc_DumpDirectoryName, fileNamePrefix ); } - // Make the filename prefix. It will have the form: + // Make the file name prefix. It will have the form: // CLI______.isabin // We'll fill in the device type and kernel name later. { @@ -10342,7 +10355,7 @@ cl_program CLIntercept::createProgramWithInjectionSPIRV( fileName += "/Inject"; } - // Make three candidate filenames. They will have the form: + // Make three candidate file names. They will have the form: // CLI___0000.spv, or // CLI__0000.spv { diff --git a/intercept/src/intercept.h b/intercept/src/intercept.h index 81351e79..5ac55b7a 100644 --- a/intercept/src/intercept.h +++ b/intercept/src/intercept.h @@ -972,7 +972,7 @@ class CLIntercept static const char* sc_ReportFileName; static const char* sc_LogFileName; static const char* sc_TraceFileName; - static const char* sc_DumpPerfCountersFileNamePrefix; + static const char* sc_PerfCountersFileNamePrefix; #if defined(CLINTERCEPT_CMAKE) static const char* sc_GitDescribe; diff --git a/intercept/src/utils.cpp b/intercept/src/utils.cpp new file mode 100644 index 00000000..f5d78738 --- /dev/null +++ b/intercept/src/utils.cpp @@ -0,0 +1,60 @@ +/* +// Copyright (c) 2024 Intel Corporation +// +// SPDX-License-Identifier: MIT +*/ + +#pragma once + +#include "utils.h" + +#include +#include +#include + +namespace Utils +{ + +std::string GetUniqueFileName(const std::string& fileName) +{ + auto fileExists = [](const std::string &name) -> bool { + std::ifstream f(name.c_str()); + return f.good(); + }; + + if (!fileExists(fileName)) + { + return fileName; + } + + // Note: Assumes that the "/" is used as a path separator! + std::size_t lastSlashPos = fileName.find_last_of("/"); + std::size_t dotPos = fileName.find_last_of('.'); + if( lastSlashPos != std::string::npos && + dotPos != std::string::npos && + dotPos < lastSlashPos ) + { + dotPos = std::string::npos; + } + + std::string baseName = + (dotPos == std::string::npos) ? + fileName : + fileName.substr(0, dotPos); + std::string extension = + (dotPos == std::string::npos) ? + "" : + fileName.substr(dotPos); + + int counter = 0; + std::string newFileName; + do + { + newFileName = baseName + "-" + std::to_string(counter++) + extension; + } + while (fileExists(newFileName)); + + return newFileName; +} + +} diff --git a/intercept/src/utils.h b/intercept/src/utils.h new file mode 100644 index 00000000..d4cfbfc7 --- /dev/null +++ b/intercept/src/utils.h @@ -0,0 +1,16 @@ +/* +// Copyright (c) 2024 Intel Corporation +// +// SPDX-License-Identifier: MIT +*/ + +#pragma once + +#include + +namespace Utils +{ + +std::string GetUniqueFileName(const std::string& fileName); + +} diff --git a/scripts/combine_chrome_traces.py b/scripts/combine_chrome_traces.py index 7fe731bf..dce5cd24 100755 --- a/scripts/combine_chrome_traces.py +++ b/scripts/combine_chrome_traces.py @@ -71,15 +71,15 @@ def main(): if len(files) < 2: print("ERROR: you must specify at least two traces to combine.") sys.exit(1) - for filename in files: - if not os.path.isfile(filename): - print("ERROR: specified file {} cannot be found.".format(filename)) + for fileName in files: + if not os.path.isfile(fileName): + print("ERROR: specified file {} cannot be found.".format(fileName)) sys.exit(1) # Read input files inputFiles = [] - for filename in files: - f = open(filename,'r') + for fileName in files: + f = open(fileName,'r') currentFile = f.readlines() f.close() inputFiles.append(currentFile)