Port ITT API Reference Collector to cross-platform Windows and Linux build (#231)
* add Windows support for ITT Reference Collector
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 659c1d6..85ef689 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -39,6 +39,36 @@
# doesn't work in case of CMake + VS (https://github.com/fortran-lang/setup-fortran/issues/45)
run: python buildall.py --force_bits 64 -ft ${{ matrix.optional_args }}
+ refcol_smoke:
+ name: Reference collector smoke test
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: ubuntu-latest
+ lib: build_linux/64/bin/libittnotify_refcol.so
+ exe: build_linux/64/bin/refcol_smoke_test
+ build_dir: build_linux/64
+ - os: windows-latest
+ lib: build_win/64/bin/libittnotify_refcol.dll
+ exe: build_win/64/bin/refcol_smoke_test.exe
+ build_dir: build_win/64
+ defaults:
+ run:
+ shell: bash
+ steps:
+ - name: Checkout sources
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ - name: Build reference collector library
+ run: python buildall.py --force_bits 64 --refcol ${{ runner.os == 'Windows' && '--cmake_gen ninja' || '' }}
+ - name: Build smoke test
+ run: |
+ cmake ${{ matrix.build_dir }} -DITT_API_REFCOL_SMOKE_TESTS=ON
+ cmake --build ${{ matrix.build_dir }} --target refcol_smoke_test
+ - name: Run smoke test
+ run: python src/ittnotify_refcol/tests/run_smoke_test.py --lib ${{ matrix.lib }} --exe ${{ matrix.exe }}
+
cpp_wrapper:
name: Check C++ wrapper
runs-on: ${{ matrix.os }}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8c97cf9..bf9dd45 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@
option(ITT_API_IPT_SUPPORT "ptmarks support" OFF)
option(ITT_API_FORTRAN_SUPPORT "fortran support" OFF)
option(ITT_API_CPP_SUPPORT "C++ wrapper support" OFF)
+option(ITT_API_REFERENCE_COLLECTOR "Build reference collector shared library" OFF)
option(ITT_API_INSTALL "Enable ITT API installation rules" ON)
if(FORCE_32 AND UNIX)
@@ -141,6 +142,10 @@
set(JITPROFILING_SRC "src/ittnotify/jitprofiling.c")
add_library(jitprofiling STATIC ${JITPROFILING_SRC})
+if(ITT_API_REFERENCE_COLLECTOR)
+ add_subdirectory(src/ittnotify_refcol)
+endif()
+
if(WIN32)
set_target_properties(ittnotify PROPERTIES OUTPUT_NAME libittnotify)
set_target_properties(jitprofiling PROPERTIES OUTPUT_NAME libjitprofiling)
diff --git a/README.md b/README.md
index 0176d25..1ae094d 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,7 @@
-ft, --fortran enable fortran support
-cpp, --cpp enable C++ wrapper support
--force_bits specify bit version for the target
+ --refcol enable reference collector build
--vs specify visual studio version (Windows only)
--cmake_gen specify cmake build generator (Windows only)
```
diff --git a/buildall.py b/buildall.py
index 180f7fe..a68a679 100755
--- a/buildall.py
+++ b/buildall.py
@@ -120,6 +120,8 @@
parser.add_argument(
"-cpp", "--cpp", help="enable C++ wrapper support", action="store_true")
parser.add_argument(
+ "--refcol", help="enable reference collector build", action="store_true")
+ parser.add_argument(
"--force_bits", choices=["32", "64"], help="specify bit version for the target")
if sys.platform == 'win32' and vs_versions:
parser.add_argument(
@@ -180,7 +182,8 @@
('-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON' if args.verbose else ''),
("-DITT_API_IPT_SUPPORT=1" if args.ptmark else ""),
("-DITT_API_FORTRAN_SUPPORT=1" if args.fortran else ""),
- ("-DITT_API_CPP_SUPPORT=ON" if args.cpp else "")
+ ("-DITT_API_CPP_SUPPORT=ON" if args.cpp else ""),
+ ("-DITT_API_REFERENCE_COLLECTOR=ON" if args.refcol else ""),
])))
if sys.platform == 'win32':
diff --git a/docs/src/build.rst b/docs/src/build.rst
index 62f6999..60de39d 100644
--- a/docs/src/build.rst
+++ b/docs/src/build.rst
@@ -56,6 +56,8 @@
-v, --verbose enable verbose output from build process
-pt, --ptmark enable anomaly detection support
-ft, --fortran enable fortran support
+ -cpp, --cpp enable C++ wrapper support
--force_bits specify bit version for the target
+ --refcol enable reference collector build
--vs specify visual studio version (Windows only)
--cmake_gen specify cmake build generator (Windows only)
diff --git a/docs/src/ref_collector.rst b/docs/src/ref_collector.rst
index 5afa5da..09dec38 100644
--- a/docs/src/ref_collector.rst
+++ b/docs/src/ref_collector.rst
@@ -7,10 +7,42 @@
This is a reference implementation of the ITT API **dynamic** part that
performs tracing data from ITT API function calls to log files.
-
To use this solution, build the collector as a shared library and point the
-full library path to the ``INTEL_LIBITTNOTIFY64`` or ``INTEL_LIBITTNOTIFY32``
-environment variable:
+full library path to the `INTEL_LIBITTNOTIFY64` or `INTEL_LIBITTNOTIFY32`
+environment variable.
+
+
+Building
+--------
+
+Use CMake from the repository root, enabling the ``ITT_API_REFERENCE_COLLECTOR`` option:
+
+.. code-block:: console
+
+ cmake -B <build_dir> -DITT_API_REFERENCE_COLLECTOR=ON
+ cmake --build <build_dir>
+
+Alternatively, use the provided ``buildall.py`` script:
+
+.. code-block:: console
+
+ python buildall.py --refcol
+
+The shared library is placed in the ``bin/`` subdirectory of the build directory:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Platform
+ - Library name
+ * - Linux
+ - ``libittnotify_refcol.so``
+ * - Windows
+ - ``libittnotify_refcol.dll``
+
+
+Usage
+-----
**On Linux**
@@ -18,8 +50,7 @@
.. code-block:: bash
- make
- export INTEL_LIBITTNOTIFY64=<build_dir>/libittnotify_refcol.so
+ export INTEL_LIBITTNOTIFY64=<build_dir>/bin/libittnotify_refcol.so
**On FreeBSD**
@@ -27,12 +58,23 @@
.. code-block:: bash
- make
- setenv INTEL_LIBITTNOTIFY64 <build_dir>/libittnotify_refcol.so
+ setenv INTEL_LIBITTNOTIFY64 <build_dir>/bin/libittnotify_refcol.so
-By default, log files save in the Temp directory. To change the location,
-use the ``INTEL_LIBITTNOTIFY_LOG_DIR`` environment variable:
+**On Windows**
+
+
+.. code-block:: bat
+
+ set INTEL_LIBITTNOTIFY64=<build_dir>\bin\libittnotify_refcol.dll
+
+
+Log File Location
+-----------------
+
+By default, log files are saved in the system temporary directory. Each run
+creates a file named ``libittnotify_refcol_<timestamp>.log``. To change the
+location, use the ``INTEL_LIBITTNOTIFY_LOG_DIR`` environment variable:
**On Linux**
@@ -40,7 +82,6 @@
.. code-block:: bash
-
export INTEL_LIBITTNOTIFY_LOG_DIR=<log_dir>
@@ -49,16 +90,25 @@
.. code-block:: bash
-
setenv INTEL_LIBITTNOTIFY_LOG_DIR <log_dir>
+**On Windows**
+
+
+.. code-block:: bat
+
+ set INTEL_LIBITTNOTIFY_LOG_DIR=<log_dir>
+
+
+Extending
+---------
+
This implementation adds logging of some of the ITT API function calls. Adding
logging of other ITT API function calls is welcome. The solution provides 4
-functions with different log levels that take ``printf`` format for logging:
+functions with different log levels that take `printf` format for logging:
-
-.. code-block:: cpp
+.. code-block:: c
LOG_FUNC_CALL_INFO(const char *msg_format, ...);
LOG_FUNC_CALL_WARN(const char *msg_format, ...);
diff --git a/src/ittnotify_refcol/CMakeLists.txt b/src/ittnotify_refcol/CMakeLists.txt
new file mode 100644
index 0000000..977c7c7
--- /dev/null
+++ b/src/ittnotify_refcol/CMakeLists.txt
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2026 Intel Corporation
+# SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
+#
+
+add_library(ittnotify_refcol SHARED itt_refcol_impl.c)
+
+target_include_directories(ittnotify_refcol
+ PUBLIC $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
+ PRIVATE ${CMAKE_SOURCE_DIR}/src/ittnotify
+)
+
+target_link_libraries(ittnotify_refcol PRIVATE ${CMAKE_DL_LIBS})
+set_target_properties(ittnotify_refcol PROPERTIES
+ LINKER_LANGUAGE C
+ RUNTIME_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+ ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH})
+
+if(WIN32)
+ target_compile_definitions(ittnotify_refcol PRIVATE _CRT_SECURE_NO_WARNINGS)
+ set_target_properties(ittnotify_refcol PROPERTIES
+ OUTPUT_NAME libittnotify_refcol
+ PREFIX ""
+ WINDOWS_EXPORT_ALL_SYMBOLS ON)
+else()
+ set_target_properties(ittnotify_refcol PROPERTIES OUTPUT_NAME ittnotify_refcol)
+endif()
+
+option(ITT_API_REFCOL_SMOKE_TESTS "Build reference collector smoke tests" OFF)
+if(ITT_API_REFCOL_SMOKE_TESTS)
+ add_executable(refcol_smoke_test tests/smoke_test.c)
+ target_include_directories(refcol_smoke_test
+ PRIVATE ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/src/ittnotify
+ )
+ target_link_libraries(refcol_smoke_test PRIVATE ittnotify ${CMAKE_DL_LIBS})
+ set_target_properties(refcol_smoke_test PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH})
+endif()
diff --git a/src/ittnotify_refcol/Makefile b/src/ittnotify_refcol/Makefile
deleted file mode 100644
index a92dc67..0000000
--- a/src/ittnotify_refcol/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-INCLUDE_DIR = ../../include/
-SRC_DIR = ../ittnotify/
-SOURCE_NAME = itt_refcol_impl.c
-OBJ_NAME = itt_refcol_impl.o
-LIB_NAME = libittnotify_refcol.so
-CC ?= gcc
-CFLAGS = -I$(INCLUDE_DIR) -I$(SRC_DIR)
-
-build:
- $(CC) -fPIC $(CFLAGS) -c $(SOURCE_NAME)
- $(CC) -shared -o $(LIB_NAME) $(OBJ_NAME)
-
-clean:
- rm $(OBJ_NAME) $(LIB_NAME)
diff --git a/src/ittnotify_refcol/README.md b/src/ittnotify_refcol/README.md
index ee30fc5..2036a56 100644
--- a/src/ittnotify_refcol/README.md
+++ b/src/ittnotify_refcol/README.md
@@ -5,24 +5,53 @@
To use this solution, build the collector as a shared library and point the
full library path to the `INTEL_LIBITTNOTIFY64` or `INTEL_LIBITTNOTIFY32`
-environment variable:
+environment variable.
+
+## Building
+
+Use CMake from the repository root, enabling the `ITT_API_REFERENCE_COLLECTOR` option:
+
+```
+cmake -B <build_dir> -DITT_API_REFERENCE_COLLECTOR=ON
+cmake --build <build_dir>
+```
+
+The shared library is placed in the `bin/` subdirectory of the CMake build
+directory. Alternatively, use the provided `buildall.py` script:
+
+```
+python buildall.py --refcol
+```
+
+The shared library is placed in the `bin/` subdirectory of the CMake build directory:
+
+| Platform | Library name |
+|----------|--------------------------------|
+| Linux | `libittnotify_refcol.so` |
+| Windows | `libittnotify_refcol.dll` |
+
+## Usage
**On Linux**
```
-make
-export INTEL_LIBITTNOTIFY64=<build_dir>/libittnotify_refcol.so
+export INTEL_LIBITTNOTIFY64=<build_dir>/bin/libittnotify_refcol.so
```
**On FreeBSD**
```
-make
-setenv INTEL_LIBITTNOTIFY64 <build_dir>/libittnotify_refcol.so
+setenv INTEL_LIBITTNOTIFY64 <build_dir>/bin/libittnotify_refcol.so
```
-By default, log files save in the `tmp` directory. To change the location,
-use the `INTEL_LIBITTNOTIFY_LOG_DIR` environment variable:
+**On Windows**
+
+```
+set INTEL_LIBITTNOTIFY64=<build_dir>\bin\libittnotify_refcol.dll
+```
+
+By default, log files are saved in the system temporary directory. To change
+the location, use the `INTEL_LIBITTNOTIFY_LOG_DIR` environment variable:
**On Linux**
@@ -35,11 +64,16 @@
setenv INTEL_LIBITTNOTIFY_LOG_DIR <log_dir>
```
+**On Windows**
+```
+set INTEL_LIBITTNOTIFY_LOG_DIR=<log_dir>
+```
+
This implementation adds logging of some of the ITT API function calls. Adding
logging of other ITT API function calls is welcome. The solution provides 4
functions with different log levels that take `printf` format for logging:
-```
+```c
LOG_FUNC_CALL_INFO(const char *msg_format, ...);
LOG_FUNC_CALL_WARN(const char *msg_format, ...);
LOG_FUNC_CALL_ERROR(const char *msg_format, ...);
diff --git a/src/ittnotify_refcol/itt_refcol_impl.c b/src/ittnotify_refcol/itt_refcol_impl.c
index 42571e8..1f245d3 100644
--- a/src/ittnotify_refcol/itt_refcol_impl.c
+++ b/src/ittnotify_refcol/itt_refcol_impl.c
@@ -4,8 +4,10 @@
SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
*/
+#include <inttypes.h>
#include <stdio.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -45,15 +47,34 @@
__itt_histogram* histogram_list;
} g_ref_collector_global = {MUTEX_INITIALIZER, 0, NULL, NULL, NULL, NULL};
+#ifdef _WIN32
+ #define REFCOL_LOCALTIME(out_tm, in_time) (localtime_s((out_tm), (in_time)) == 0)
+#else
+ #define REFCOL_LOCALTIME(out_tm, in_time) (localtime_r((in_time), (out_tm)) != NULL)
+#endif
+
static char* log_file_name_generate()
{
time_t time_now = time(NULL);
- struct tm* time_info = localtime(&time_now);
+ struct tm time_info;
char* log_file_name = malloc(sizeof(char) * (LOG_BUFFER_MAX_SIZE/2));
- sprintf(log_file_name,"libittnotify_refcol_%d%d%d%d%d%d.log",
- time_info->tm_year+1900, time_info->tm_mon+1, time_info->tm_mday,
- time_info->tm_hour, time_info->tm_min, time_info->tm_sec);
+ if (log_file_name == NULL)
+ {
+ printf("ERROR: Failed to allocate memory for log file name\n");
+ return NULL;
+ }
+
+ if (!REFCOL_LOCALTIME(&time_info, &time_now))
+ {
+ printf("ERROR: Failed to get local time for log file name\n");
+ free(log_file_name);
+ return NULL;
+ }
+
+ snprintf(log_file_name, LOG_BUFFER_MAX_SIZE/2, "libittnotify_refcol_%d%d%d%d%d%d.log",
+ time_info.tm_year+1900, time_info.tm_mon+1, time_info.tm_mday,
+ time_info.tm_hour, time_info.tm_min, time_info.tm_sec);
return log_file_name;
}
@@ -72,9 +93,9 @@
if (log_dir != NULL)
{
#ifdef _WIN32
- sprintf(file_name_buffer,"%s\\%s", log_dir, log_file);
+ snprintf(file_name_buffer, sizeof(file_name_buffer), "%s\\%s", log_dir, log_file);
#else
- sprintf(file_name_buffer,"%s/%s", log_dir, log_file);
+ snprintf(file_name_buffer, sizeof(file_name_buffer), "%s/%s", log_dir, log_file);
#endif
}
else
@@ -83,10 +104,14 @@
char* temp_dir = getenv("TEMP");
if (temp_dir != NULL)
{
- sprintf(file_name_buffer,"%s\\%s", temp_dir, log_file);
+ snprintf(file_name_buffer, sizeof(file_name_buffer), "%s\\%s", temp_dir, log_file);
+ }
+ else
+ {
+ snprintf(file_name_buffer, sizeof(file_name_buffer), "%s", log_file);
}
#else
- sprintf(file_name_buffer,"/tmp/%s", log_file);
+ snprintf(file_name_buffer, sizeof(file_name_buffer), "/tmp/%s", log_file);
#endif
}
free(log_file);
@@ -122,7 +147,7 @@
// Cleanup hook called at program exit via atexit().
// Releases all resources: closes log file, frees all ITT objects.
-static void ref_collector_release()
+static void ref_collector_release(void)
{
static int released = 0;
if (released) return;
@@ -261,7 +286,9 @@
uint32_t result_len = 0;
va_list message_args;
- result_len += sprintf(log_buffer, "[%s] %s(...) - ", log_level_str[log_level] ,function_name);
+ result_len += snprintf(log_buffer, LOG_BUFFER_MAX_SIZE, "[%s] %s(...) - ", log_level_str[log_level], function_name);
+ if (result_len >= LOG_BUFFER_MAX_SIZE)
+ result_len = LOG_BUFFER_MAX_SIZE - 1;
va_start(message_args, message_format);
vsnprintf(log_buffer + result_len, LOG_BUFFER_MAX_SIZE - result_len, message_format, message_args);
va_end(message_args);
@@ -292,36 +319,36 @@
switch (type)
{
case __itt_metadata_u64:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%lu;", ((uint64_t*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%" PRIu64 ";", ((uint64_t*)metadata)[i]);
break;
case __itt_metadata_s64:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%ld;", ((int64_t*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%" PRId64 ";", ((int64_t*)metadata)[i]);
break;
case __itt_metadata_u32:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%u;", ((uint32_t*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%u;", ((uint32_t*)metadata)[i]);
break;
case __itt_metadata_s32:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%d;", ((int32_t*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%d;", ((int32_t*)metadata)[i]);
break;
case __itt_metadata_u16:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%u;", ((uint16_t*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%u;", ((uint16_t*)metadata)[i]);
break;
case __itt_metadata_s16:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%d;", ((int16_t*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%d;", ((int16_t*)metadata)[i]);
break;
case __itt_metadata_float:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%f;", ((float*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%f;", ((float*)metadata)[i]);
break;
case __itt_metadata_double:
- for (uint16_t i = 0; i < size; i++)
- offset += sprintf(metadata_str + offset, "%lf;", ((double*)metadata)[i]);
+ for (uint16_t i = 0; i < size && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
+ offset += snprintf(metadata_str + offset, LOG_BUFFER_MAX_SIZE - offset, "%lf;", ((double*)metadata)[i]);
break;
default:
printf("ERROR: Unknown metadata type\n");
@@ -343,7 +370,7 @@
case __itt_context_device:
case __itt_context_units:
case __itt_context_pci_addr:
- sprintf(metadata_str, "%s;", ((char*)metadata));
+ snprintf(metadata_str, LOG_BUFFER_MAX_SIZE/4, "%s;", ((char*)metadata));
break;
case __itt_context_max_val:
case __itt_context_tid:
@@ -354,7 +381,7 @@
case __itt_context_cpu_instructions_flag:
case __itt_context_cpu_cycles_flag:
case __itt_context_is_abs_val_flag:
- sprintf(metadata_str, "%lu;", *(uint64_t*)metadata);
+ snprintf(metadata_str, LOG_BUFFER_MAX_SIZE/4, "%" PRIu64 ";", *(uint64_t*)metadata);
break;
default:
printf("ERROR: Unknown context metadata type\n");
@@ -364,7 +391,48 @@
return metadata_str;
}
+#ifdef _WIN32
+static char* wchar2char(const wchar_t* wide_str)
+{
+ if (wide_str == NULL)
+ {
+ return NULL;
+ }
+
+ int narrow_size = WideCharToMultiByte(CP_UTF8, 0, wide_str, -1, NULL, 0, NULL, NULL);
+ if (narrow_size <= 0)
+ {
+ return NULL;
+ }
+
+ char* narrow_str = (char*)malloc((size_t)narrow_size);
+ if (narrow_str == NULL)
+ {
+ return NULL;
+ }
+
+ if (!WideCharToMultiByte(CP_UTF8, 0, wide_str, -1, narrow_str, narrow_size, NULL, NULL))
+ {
+ free(narrow_str);
+ return NULL;
+ }
+
+ return narrow_str;
+}
+#endif
+
+#ifdef _WIN32
+ITT_EXTERN_C __itt_domain* ITTAPI __itt_domain_createW(const wchar_t *name)
+{
+ char* name_a = wchar2char(name);
+ __itt_domain* result = __itt_domain_createA(name_a);
+ free(name_a);
+ return result;
+}
+ITT_EXTERN_C __itt_domain* ITTAPI __itt_domain_createA(const char *name)
+#else
ITT_EXTERN_C __itt_domain* ITTAPI __itt_domain_create(const char *name)
+#endif
{
if (!g_ref_collector_global.mutex_initialized || name == NULL)
{
@@ -396,7 +464,18 @@
return h;
}
+#ifdef _WIN32
+ITT_EXTERN_C __itt_string_handle* ITTAPI __itt_string_handle_createW(const wchar_t* name)
+{
+ char* name_a = wchar2char(name);
+ __itt_string_handle* result = __itt_string_handle_createA(name_a);
+ free(name_a);
+ return result;
+}
+ITT_EXTERN_C __itt_string_handle* ITTAPI __itt_string_handle_createA(const char* name)
+#else
ITT_EXTERN_C __itt_string_handle* ITTAPI __itt_string_handle_create(const char* name)
+#endif
{
if (!g_ref_collector_global.mutex_initialized || name == NULL)
{
@@ -428,21 +507,69 @@
return h;
}
+#ifdef _WIN32
+ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_createW(const wchar_t *name, const wchar_t *domain)
+{
+ char* name_a = wchar2char(name);
+ char* domain_a = wchar2char(domain);
+ __itt_counter result = __itt_counter_createA(name_a, domain_a);
+ free(name_a);
+ free(domain_a);
+ return result;
+}
+ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_createA(const char *name, const char *domain)
+#else
ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_create(const char *name, const char *domain)
+#endif
{
LOG_FUNC_CALL_INFO("function call");
return __itt_counter_create_typed(name, domain, __itt_metadata_u64);
}
+#ifdef _WIN32
+ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_createW_v3(
+ const __itt_domain* domain, const wchar_t* name, __itt_metadata_type type)
+{
+ if (domain == NULL) return NULL;
+ char* name_a = wchar2char(name);
+ if (name_a == NULL) return NULL;
+ __itt_counter result = __itt_counter_create_typed(name_a, domain->nameA, type);
+ free(name_a);
+ return result;
+}
+ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_createA_v3(
+ const __itt_domain* domain, const char* name, __itt_metadata_type type)
+#else
ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_create_v3(
const __itt_domain* domain, const char* name, __itt_metadata_type type)
+#endif
{
+ if (domain == NULL)
+ {
+ LOG_FUNC_CALL_WARN("domain is NULL");
+ return NULL;
+ }
LOG_FUNC_CALL_INFO("function call");
return __itt_counter_create_typed(name, domain->nameA, type);
}
+#ifdef _WIN32
+ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_create_typedW(
+ const wchar_t *name, const wchar_t *domain, __itt_metadata_type type)
+{
+ char* name_a = wchar2char(name);
+ char* domain_a = wchar2char(domain);
+ __itt_counter result = __itt_counter_create_typedA(name_a, domain_a, type);
+ free(name_a);
+ free(domain_a);
+ return result;
+}
+ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_create_typedA(
+ const char *name, const char *domain, __itt_metadata_type type)
+#else
ITT_EXTERN_C __itt_counter ITTAPI __itt_counter_create_typed(
const char *name, const char *domain, __itt_metadata_type type)
+#endif
{
if (!g_ref_collector_global.mutex_initialized || name == NULL || domain == NULL)
{
@@ -478,8 +605,21 @@
return (__itt_counter)h;
}
+#ifdef _WIN32
+ITT_EXTERN_C __itt_histogram* ITTAPI __itt_histogram_createW(
+ const __itt_domain* domain, const wchar_t* name, __itt_metadata_type x_type, __itt_metadata_type y_type)
+{
+ char* name_a = wchar2char(name);
+ __itt_histogram* result = __itt_histogram_createA(domain, name_a, x_type, y_type);
+ free(name_a);
+ return result;
+}
+ITT_EXTERN_C __itt_histogram* ITTAPI __itt_histogram_createA(
+ const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type)
+#else
ITT_EXTERN_C __itt_histogram* ITTAPI __itt_histogram_create(
const __itt_domain* domain, const char* name, __itt_metadata_type x_type, __itt_metadata_type y_type)
+#endif
{
if (!g_ref_collector_global.mutex_initialized || name == NULL || domain == NULL)
{
@@ -644,7 +784,7 @@
(void)id;
(void)key;
char* metadata_str = get_metadata_elements(count, type, data);
- LOG_FUNC_CALL_INFO("function args: domain=%s metadata_size=%lu metadata[]=%s",
+ LOG_FUNC_CALL_INFO("function args: domain=%s metadata_size=%zu metadata[]=%s",
domain->nameA, count, metadata_str);
free(metadata_str);
}
@@ -690,7 +830,7 @@
{
char* x_data_str = get_metadata_elements(length, hist->x_type, x_data);
char* y_data_str = get_metadata_elements(length, hist->y_type, y_data);
- LOG_FUNC_CALL_INFO("function args: domain=%s name=%s histogram_size=%lu x[]=%s y[]=%s",
+ LOG_FUNC_CALL_INFO("function args: domain=%s name=%s histogram_size=%zu x[]=%s y[]=%s",
hist->domain->nameA, hist->nameA, length, x_data_str, y_data_str);
free(x_data_str);
free(y_data_str);
@@ -698,7 +838,7 @@
else
{
char* y_data_str = get_metadata_elements(length, hist->y_type, y_data);
- LOG_FUNC_CALL_INFO("function args: domain=%s name=%s histogram_size=%lu y[]=%s",
+ LOG_FUNC_CALL_INFO("function args: domain=%s name=%s histogram_size=%zu y[]=%s",
hist->domain->nameA, hist->nameA, length, y_data_str);
free(y_data_str);
}
@@ -717,13 +857,13 @@
char context_metadata[LOG_BUFFER_MAX_SIZE];
context_metadata[0] = '\0';
uint16_t offset = 0;
- for(size_t i=0; i<length; i++)
+ for(size_t i=0; i<length && offset < LOG_BUFFER_MAX_SIZE - 1; i++)
{
char* context_metadata_element = get_context_metadata_element(metadata[i].type, metadata[i].value);
- offset += sprintf(context_metadata+ offset, "%s", context_metadata_element);
+ offset += snprintf(context_metadata + offset, LOG_BUFFER_MAX_SIZE - offset, "%s", context_metadata_element);
free(context_metadata_element);
}
- LOG_FUNC_CALL_INFO("function args: counter_name=%s context_metadata_size=%lu context_metadata[]=%s",
+ LOG_FUNC_CALL_INFO("function args: counter_name=%s context_metadata_size=%zu context_metadata[]=%s",
counter_info->nameA, length, context_metadata);
}
else
@@ -738,7 +878,7 @@
{
__itt_counter_info_t* counter_info = (__itt_counter_info_t*)counter;
uint64_t value = *(uint64_t*)value_ptr;
- LOG_FUNC_CALL_INFO("function args: counter_name=%s counter_value=%lu",
+ LOG_FUNC_CALL_INFO("function args: counter_name=%s counter_value=%" PRIu64,
counter_info->nameA, value);
}
else
diff --git a/src/ittnotify_refcol/tests/run_smoke_test.py b/src/ittnotify_refcol/tests/run_smoke_test.py
new file mode 100644
index 0000000..cea0c65
--- /dev/null
+++ b/src/ittnotify_refcol/tests/run_smoke_test.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2026 Intel Corporation
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+#
+
+import argparse
+import glob
+import os
+import subprocess
+import sys
+import tempfile
+
+
+EXPECTED_SYMBOLS = [
+ "__itt_task_begin",
+ "__itt_task_end",
+ "__itt_metadata_add",
+]
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Run reference collector smoke test")
+ parser.add_argument("--lib", required=True, help="Path to libittnotify_refcol shared library")
+ parser.add_argument("--exe", required=True, help="Path to refcol_smoke_test executable")
+ parser.add_argument("--log-dir", help="Directory for log files (default: temp dir)")
+ args = parser.parse_args()
+
+ lib = os.path.abspath(args.lib)
+ exe = os.path.abspath(args.exe)
+
+ if not os.path.isfile(lib):
+ print(f"ERROR: library not found: {lib}")
+ return 1
+ if not os.path.isfile(exe):
+ print(f"ERROR: executable not found: {exe}")
+ return 1
+
+ log_dir = os.path.abspath(args.log_dir) if args.log_dir else tempfile.mkdtemp(prefix="refcol_logs_")
+ os.makedirs(log_dir, exist_ok=True)
+
+ env = os.environ.copy()
+ env["INTEL_LIBITTNOTIFY64"] = lib
+ env["INTEL_LIBITTNOTIFY_LOG_DIR"] = log_dir
+
+ print(f"Library: {lib}")
+ print(f"Exe: {exe}")
+ print(f"Log dir: {log_dir}")
+
+ result = subprocess.run([exe], env=env)
+ if result.returncode != 0:
+ print(f"ERROR: smoke test executable exited with code {result.returncode}")
+ return 1
+
+ logs = glob.glob(os.path.join(log_dir, "libittnotify_refcol_*.log"))
+ if not logs:
+ print("ERROR: no log file found in", log_dir)
+ return 1
+
+ log_path = logs[0]
+ print(f"Log file: {log_path}")
+
+ with open(log_path, encoding="utf-8", errors="replace") as f:
+ content = f.read()
+
+ missing = [sym for sym in EXPECTED_SYMBOLS if sym not in content]
+ if missing:
+ for sym in missing:
+ print(f"ERROR: '{sym}' not found in log")
+ return 1
+
+ print("Smoke test passed.")
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/src/ittnotify_refcol/tests/smoke_test.c b/src/ittnotify_refcol/tests/smoke_test.c
new file mode 100644
index 0000000..4c2a5bf
--- /dev/null
+++ b/src/ittnotify_refcol/tests/smoke_test.c
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2026 Intel Corporation
+
+ SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
+*/
+
+#include "ittnotify.h"
+#include "ittnotify_types.h"
+
+int main(void)
+{
+ __itt_domain* domain = __itt_domain_create("smoke_test_domain");
+ __itt_string_handle* handle = __itt_string_handle_create("smoke_test_handler");
+ __itt_string_handle* handle_work = __itt_string_handle_create("smoke_test_worker");
+
+ const int n = 10;
+ int a[10][10], b[10][10], mul[10][10], i, j, k, count = 0;
+
+ for (i = 0; i < n; i++)
+ for (j = 0; j < n; j++)
+ {
+ a[i][j] = i;
+ b[i][j] = j;
+ mul[i][j] = 0;
+ }
+
+ for (i = 0; i < n; i++)
+ for (j = 0; j < n; j++)
+ for (k = 0; k < n; k++)
+ {
+ mul[i][j] += a[i][k] * b[k][j];
+ count++;
+ if (count % 100 == 0)
+ {
+ __itt_task_begin(domain, __itt_null, __itt_null, handle_work);
+ unsigned long long data[5] = { i, j, k, count, mul[i][j] };
+ __itt_metadata_add(domain, __itt_null, handle, __itt_metadata_u64, 5, data);
+ __itt_task_end(domain);
+ }
+ }
+
+ return 0;
+}