Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:45:12

0001 /*
0002  * SPDX-FileCopyrightText: Copyright (c) 2009-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
0003  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0004  *
0005  * Licensed under the Apache License, Version 2.0 (the "License");
0006  * you may not use this file except in compliance with the License.
0007  * You may obtain a copy of the License at
0008  *
0009  *     http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  *
0017  * Licensed under the Apache License v2.0 with LLVM Exceptions.
0018  * See https://nvidia.github.io/NVTX/LICENSE.txt for license information.
0019  */
0020 
0021 #ifndef NVTX_EXT_INIT_GUARD
0022 #error Never include this file directly -- it is automatically included by nvToolsExt.h (except when NVTX_NO_IMPL is defined).
0023 #endif
0024 
0025 #if defined(NVTX_AS_SYSTEM_HEADER)
0026 #if defined(__clang__)
0027 #pragma clang system_header
0028 #elif defined(__GNUC__) || defined(__NVCOMPILER)
0029 #pragma GCC system_header
0030 #elif defined(_MSC_VER)
0031 #pragma system_header
0032 #endif
0033 #endif
0034 
0035 #ifdef __cplusplus
0036 extern "C" {
0037 #endif /* __cplusplus */
0038 
0039 /* ---- Platform-independent helper definitions and functions ---- */
0040 
0041 /* Prefer macros over inline functions to reduce symbol resolution at link time */
0042 
0043 #if defined(_WIN32)
0044 #define NVTX_ATOMIC_WRITE_PTR(address, value) \
0045     InterlockedExchangePointer(NVTX_REINTERPRET_CAST(volatile PVOID*, (address)), \
0046         NVTX_REINTERPRET_CAST(PVOID, (value)))
0047 #define NVTX_ATOMIC_CAS_PTR(old, address, exchange, comparand) \
0048     (old) = NVTX_REINTERPRET_CAST(intptr_t, InterlockedCompareExchangePointer( \
0049         NVTX_REINTERPRET_CAST(volatile PVOID*, (address)), \
0050         NVTX_REINTERPRET_CAST(PVOID, (exchange)), \
0051         NVTX_REINTERPRET_CAST(PVOID, (comparand))))
0052 #elif defined(__GNUC__)
0053 /* Ensure full memory barrier for atomics, to match Windows functions */
0054 #define NVTX_ATOMIC_WRITE_PTR(address, value) \
0055     __sync_synchronize(); *address = value; __sync_synchronize()
0056 #define NVTX_ATOMIC_CAS_PTR(old, address, exchange, comparand) \
0057     old = __sync_val_compare_and_swap(address, comparand, exchange)
0058 #else
0059 #error The library does not support your configuration!
0060 #endif
0061 
0062 #ifndef NVTX_SUPPORT_ALREADY_INJECTED_LIBRARY
0063 /* Define this to 1 for platforms that where pre-injected libraries can be discovered. */
0064 #if defined(_WIN32)
0065 /* Windows has no process-wide table of dynamic library symbols, so this can't be supported. */
0066 #define NVTX_SUPPORT_ALREADY_INJECTED_LIBRARY 0
0067 #else
0068 /* POSIX platforms allow calling dlsym on a null module to use the process-wide table.
0069  * Note: Still disabled in load sequence version 2.  Needs to support following the
0070  * RTLD_NEXT chain, and needs more testing before support can be enabled by default. */
0071 #define NVTX_SUPPORT_ALREADY_INJECTED_LIBRARY 0
0072 #endif
0073 #endif
0074 
0075 #ifndef NVTX_SUPPORT_ENV_VARS
0076 /* Define this to 1 for platforms that support environment variables. */
0077 /* TODO: Detect UWP, a.k.a. Windows Store app, and set this to 0. */
0078 /* Try:  #if defined(WINAPI_FAMILY_PARTITION) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) */
0079 #define NVTX_SUPPORT_ENV_VARS 1
0080 #endif
0081 
0082 #ifndef NVTX_SUPPORT_DYNAMIC_INJECTION_LIBRARY
0083 /* Define this to 1 for platforms that support dynamic/shared libraries */
0084 #define NVTX_SUPPORT_DYNAMIC_INJECTION_LIBRARY 1
0085 #endif
0086 
0087 #ifndef NVTX_SUPPORT_ANDROID_INJECTION_LIBRARY_IN_PACKAGE
0088 #if defined(__ANDROID__)
0089 #define NVTX_SUPPORT_ANDROID_INJECTION_LIBRARY_IN_PACKAGE 1
0090 #else
0091 #define NVTX_SUPPORT_ANDROID_INJECTION_LIBRARY_IN_PACKAGE 0
0092 #endif
0093 #endif
0094 
0095 #ifndef NVTX_SUPPORT_STATIC_INJECTION_LIBRARY
0096 /* On platforms that support weak symbols (i.e. non-Windows), injection libraries may
0097 *  be statically linked into an application.  This is useful for platforms where dynamic
0098 *  injection is not available.  Weak symbols not marked extern are definitions, not just
0099 *  declarations.  They are guaranteed to be initialized to zero if no normal definitions
0100 *  are found by the linker to override them.  This means the NVTX load sequence can safely
0101 *  detect the presence of a static injection -- if InitializeInjectionNvtxExtension_fnptr is zero,
0102 *  there is no static injection. */
0103 #if defined(__GNUC__) && !defined(_WIN32) && !defined(__CYGWIN__)
0104 #define NVTX_SUPPORT_STATIC_INJECTION_LIBRARY 1
0105 #else
0106 #define NVTX_SUPPORT_STATIC_INJECTION_LIBRARY 0
0107 #endif
0108 #endif
0109 
0110 #if NVTX_SUPPORT_STATIC_INJECTION_LIBRARY && !defined(NVTX_STATIC_INJECTION_IMPL)
0111 /* To make an NVTX injection library support static injection, it must do these things:
0112 *  - Define InitializeInjectionNvtxExtension_fnptr as a normal symbol (not weak), pointing to
0113 *    the implementation of InitializeInjectionNvtxExtension (which does not need to be a
0114 *    dynamic export if only supporting static injection).
0115 *  - Define NVTX_STATIC_INJECTION_IMPL so the weak definition below is skipped.
0116 *  - Compile the static injection files with -fPIC if they are to be linked with other
0117 *    files compiled this way.  If you forget this, GCC will simply tell you to add it.
0118 *  When building the application, there a few ways to link in a static injection:
0119 *  - Compile the injection's source files normally, and include the .o files as inputs
0120 *    to the linker.
0121 *  - If the injection is provided as an archive (.a file), it will not resolve any
0122 *    unresolved symbols, so the linker will skip it by default.  This can be fixed
0123 *    by wrapping the static injection's name on the linker command line with options
0124 *    to treat it differently.  For example:
0125 *      gcc example.o libfoo.a -Wl,--whole-archive libinj-static.a -Wl,--no-whole-archive libbar.a
0126 *    Note that libinj-static.a is bracketed by options to turn on "whole archive" and
0127 *    then back off again afterwards, so libfoo.a and libbar.a are linked normally.
0128 *  - In CMake, a static injection can be added with options like this:
0129 *      target_link_libraries(app PRIVATE -Wl,--whole-archive inj-static -Wl,--no-whole-archive)
0130 */
0131 __attribute__((weak)) NvtxExtInitializeInjectionFunc_t InitializeInjectionNvtxExtension_fnptr;
0132 #endif
0133 
0134 /* This function tries to find or load an NVTX injection library and get the
0135 *  address of its InitializeInjectionExtension function.  If such a function pointer
0136 *  is found, it is called, and passed the address of this NVTX instance's
0137 *  nvtxGetExportTable function, so the injection can attach to this instance.
0138 *  If the initialization fails for any reason, any dynamic library loaded will
0139 *  be freed, and all NVTX implementation functions will be set to no-ops.  If
0140 *  initialization succeeds, NVTX functions not attached to the tool will be set
0141 *  to no-ops.  This is implemented as one function instead of several small
0142 *  functions to minimize the number of weak symbols the linker must resolve.
0143 *  Order of search is:
0144 *  - Pre-injected library exporting InitializeInjectionNvtxExtension
0145 *  - Loadable library exporting InitializeInjectionNvtxExtension
0146 *      - Path specified by env var NVTX_INJECTION??_PATH (?? is 32 or 64)
0147 *      - On Android, libNvtxInjection??.so within the package (?? is 32 or 64)
0148 *  - Statically-linked injection library defining InitializeInjectionNvtxExtension_fnptr
0149 */
0150 NVTX_LINKONCE_FWDDECL_FUNCTION int NVTX_VERSIONED_IDENTIFIER(nvtxExtLoadInjectionLibrary)(
0151     NvtxExtInitializeInjectionFunc_t* out_init_fnptr);
0152 NVTX_LINKONCE_DEFINE_FUNCTION int NVTX_VERSIONED_IDENTIFIER(nvtxExtLoadInjectionLibrary)(
0153     NvtxExtInitializeInjectionFunc_t* out_init_fnptr)
0154 {
0155     static const char initFuncName[] = "InitializeInjectionNvtxExtension";
0156 #if NVTX_SUPPORT_ALREADY_INJECTED_LIBRARY
0157     static const char initFuncPreinjectName[] = "InitializeInjectionNvtxExtensionPreinject";
0158 #endif
0159     NvtxExtInitializeInjectionFunc_t init_fnptr = NVTX_NULLPTR;
0160     NVTX_DLLHANDLE injectionLibraryHandle = NVTX_DLLDEFAULT;
0161 
0162     if (out_init_fnptr)
0163     {
0164         *out_init_fnptr = NVTX_NULLPTR;
0165     }
0166 
0167 #if NVTX_SUPPORT_DYNAMIC_INJECTION_LIBRARY
0168     /* Try discovering dynamic injection library to load */
0169     {
0170 #if NVTX_SUPPORT_ENV_VARS
0171         /* If env var NVTX_INJECTION64_PATH is set, it should contain the path
0172            to a 64-bit dynamic NVTX injection library (and similar for 32-bit). */
0173         const NVTX_PATHCHAR* const nvtxEnvVarName = (sizeof(void*) == 4)
0174             ? NVTX_STR("NVTX_INJECTION32_PATH")
0175             : NVTX_STR("NVTX_INJECTION64_PATH");
0176 #endif /* NVTX_SUPPORT_ENV_VARS */
0177         NVTX_PATHCHAR injectionLibraryPathBuf[NVTX_BUFSIZE];
0178         const NVTX_PATHCHAR* injectionLibraryPath = NVTX_NULLPTR;
0179 
0180         /* Refer to this variable explicitly in case all references to it are #if'ed out. */
0181         (void)injectionLibraryPathBuf;
0182 
0183 #if NVTX_SUPPORT_ENV_VARS
0184         /* Disable the warning for getenv & _wgetenv -- this usage is safe because
0185            these functions are not called again before using the returned value. */
0186 #if defined(_MSC_VER)
0187 #pragma warning( push )
0188 #pragma warning( disable : 4996 )
0189 #endif
0190         injectionLibraryPath = NVTX_GETENV(nvtxEnvVarName);
0191 #if defined(_MSC_VER)
0192 #pragma warning( pop )
0193 #endif
0194 #endif
0195 
0196 #if NVTX_SUPPORT_ANDROID_INJECTION_LIBRARY_IN_PACKAGE
0197         if (!injectionLibraryPath)
0198         {
0199             const char *bits = (sizeof(void*) == 4) ? "32" : "64";
0200             char cmdlineBuf[32];
0201             char pkgName[PATH_MAX];
0202             int count;
0203             int pid;
0204             FILE *fp;
0205             size_t bytesRead;
0206             size_t pos;
0207 
0208             pid = NVTX_STATIC_CAST(int, getpid());
0209             count = snprintf(cmdlineBuf, sizeof(cmdlineBuf), "/proc/%d/cmdline", pid);
0210             if (count <= 0 || count >= NVTX_STATIC_CAST(int, sizeof(cmdlineBuf)))
0211             {
0212                 NVTX_ERR("Path buffer too small for: /proc/%d/cmdline\n", pid);
0213                 return NVTX_ERR_INIT_ACCESS_LIBRARY;
0214             }
0215 
0216             fp = fopen(cmdlineBuf, "r");
0217             if (!fp)
0218             {
0219                 NVTX_ERR("File couldn't be opened: %s\n", cmdlineBuf);
0220                 return NVTX_ERR_INIT_ACCESS_LIBRARY;
0221             }
0222 
0223             bytesRead = fread(pkgName, 1, sizeof(pkgName) - 1, fp);
0224             fclose(fp);
0225             if (bytesRead == 0)
0226             {
0227                 NVTX_ERR("Package name couldn't be read from file: %s\n", cmdlineBuf);
0228                 return NVTX_ERR_INIT_ACCESS_LIBRARY;
0229             }
0230 
0231             pkgName[bytesRead] = 0;
0232 
0233             /* String can contain colon as a process separator. In this case the
0234                package name is before the colon. */
0235             pos = 0;
0236             while (pos < bytesRead && pkgName[pos] != ':' && pkgName[pos] != '\0')
0237             {
0238                 ++pos;
0239             }
0240             pkgName[pos] = 0;
0241 
0242             count = snprintf(injectionLibraryPathBuf, NVTX_BUFSIZE, "/data/data/%s/files/libNvtxInjection%s.so", pkgName, bits);
0243             if (count <= 0 || count >= NVTX_BUFSIZE)
0244             {
0245                 NVTX_ERR("Path buffer too small for: /data/data/%s/files/libNvtxInjection%s.so\n", pkgName, bits);
0246                 return NVTX_ERR_INIT_ACCESS_LIBRARY;
0247             }
0248 
0249             /* On Android, verify path is accessible due to aggressive file access restrictions. */
0250             /* For dlopen, if the filename contains a leading slash, then it is interpreted as a */
0251             /* relative or absolute pathname; otherwise it will follow the rules in ld.so. */
0252             if (injectionLibraryPathBuf[0] == '/')
0253             {
0254 #if (__ANDROID_API__ < 21)
0255                 int access_err = access(injectionLibraryPathBuf, F_OK | R_OK);
0256 #else
0257                 int access_err = faccessat(AT_FDCWD, injectionLibraryPathBuf, F_OK | R_OK, 0);
0258 #endif
0259                 if (access_err != 0)
0260                 {
0261                     NVTX_ERR("Injection library path wasn't accessible [code=%s] [path=%s]\n", strerror(errno), injectionLibraryPathBuf);
0262                     return NVTX_ERR_INIT_ACCESS_LIBRARY;
0263                 }
0264             }
0265             injectionLibraryPath = injectionLibraryPathBuf;
0266         }
0267 #endif /* NVTX_SUPPORT_ANDROID_INJECTION_LIBRARY_IN_PACKAGE */
0268 
0269         /* At this point, `injectionLibraryPath` is specified if a dynamic
0270            injection library was specified by a tool. */
0271         if (injectionLibraryPath)
0272         {
0273             /* Load the injection library */
0274             injectionLibraryHandle = NVTX_DLLOPEN(injectionLibraryPath);
0275             if (!injectionLibraryHandle)
0276             {
0277                 NVTX_ERR("Failed to load injection library\n");
0278                 return NVTX_ERR_INIT_LOAD_LIBRARY;
0279             }
0280             else
0281             {
0282                 /* Attempt to get the injection library's entry-point. */
0283                 init_fnptr = NVTX_REINTERPRET_CAST(NvtxExtInitializeInjectionFunc_t, NVTX_DLLFUNC(injectionLibraryHandle, initFuncName));
0284                 if (!init_fnptr)
0285                 {
0286                     NVTX_DLLCLOSE(injectionLibraryHandle);
0287                     NVTX_ERR("Failed to get address of function %s from injection library\n", initFuncName);
0288                     return NVTX_ERR_INIT_MISSING_LIBRARY_ENTRY_POINT;
0289                 }
0290             }
0291         }
0292     }
0293 #endif /* NVTX_SUPPORT_DYNAMIC_INJECTION_LIBRARY */
0294 
0295 #if NVTX_SUPPORT_ALREADY_INJECTED_LIBRARY
0296     if (!init_fnptr)
0297     {
0298         /* Use POSIX global symbol chain to query for init function from any module */
0299         init_fnptr = NVTX_REINTERPRET_CAST(NvtxExtInitializeInjectionFunc_t, NVTX_DLLFUNC(NVTX_DLLDEFAULT, initFuncPreinjectName));
0300     }
0301 #endif
0302 
0303 #if NVTX_SUPPORT_STATIC_INJECTION_LIBRARY
0304     if (!init_fnptr)
0305     {
0306         /* Check weakly-defined function pointer.  A statically-linked injection can define this
0307         *  as a normal symbol and set it to the address of the NVTX init function -- this will
0308         *  provide a non-null value here.  If there is no other definition of this symbol, it
0309         *  will be null here. */
0310         if (InitializeInjectionNvtxExtension_fnptr)
0311         {
0312             init_fnptr = InitializeInjectionNvtxExtension_fnptr;
0313         }
0314     }
0315 #endif
0316 
0317     if (out_init_fnptr)
0318     {
0319         *out_init_fnptr = init_fnptr;
0320     }
0321 
0322     /* At this point, if `init_fnptr` is not set, no tool has specified an NVTX injection library.
0323        Non-success result is returned, so that all NVTX API functions will be set to no-ops. */
0324     if (!init_fnptr)
0325     {
0326         return NVTX_ERR_NO_INJECTION_LIBRARY_AVAILABLE;
0327     }
0328 
0329     return NVTX_SUCCESS;
0330 }
0331 
0332 /* Avoid warnings about missing prototypes. */
0333 NVTX_LINKONCE_FWDDECL_FUNCTION void NVTX_VERSIONED_IDENTIFIER(nvtxExtInitOnce) (
0334     nvtxExtModuleInfo_t* moduleInfo, intptr_t* moduleState);
0335 NVTX_LINKONCE_DEFINE_FUNCTION void NVTX_VERSIONED_IDENTIFIER(nvtxExtInitOnce) (
0336     nvtxExtModuleInfo_t* moduleInfo, intptr_t* moduleState)
0337 {
0338     intptr_t old;
0339 
0340     NVTX_INFO( "%s\n", __FUNCTION__ );
0341 
0342     if (*moduleState == NVTX_EXTENSION_LOADED ||
0343         *moduleState == NVTX_EXTENSION_DISABLED ||
0344         *moduleState == NVTX_EXTENSION_INIT_FN_FAILED)
0345     {
0346         NVTX_INFO("Module loaded\n");
0347         return;
0348     }
0349 
0350     NVTX_ATOMIC_CAS_PTR(
0351         old,
0352         moduleState,
0353         NVTX_EXTENSION_STARTING,
0354         NVTX_EXTENSION_FRESH);
0355     if (old == NVTX_EXTENSION_FRESH)
0356     {
0357         intptr_t stateReturnValue = NVTX_EXTENSION_LOADED;
0358         NvtxExtInitializeInjectionFunc_t init_fnptr =
0359             NVTX_VERSIONED_IDENTIFIER(nvtxExtGlobals1).injectionFnPtr;
0360         int entryPointStatus = 0;
0361         int forceAllToNoops = 0;
0362         size_t s;
0363 
0364         /* Load and initialize injection library, which will assign the function pointers. */
0365         if (init_fnptr == NVTX_NULLPTR)
0366         {
0367             int result = 0;
0368 
0369             /* Try to load vanilla NVTX first. */
0370             nvtxInitialize(NVTX_NULLPTR);
0371 
0372             result = NVTX_VERSIONED_IDENTIFIER(nvtxExtLoadInjectionLibrary)(&init_fnptr);
0373             /* At this point `init_fnptr` will be either 0 or a real function. */
0374 
0375             if (result == NVTX_SUCCESS)
0376             {
0377                 NVTX_VERSIONED_IDENTIFIER(nvtxExtGlobals1).injectionFnPtr = init_fnptr;
0378             }
0379             else
0380             {
0381                 if (result == NVTX_ERR_INIT_MISSING_LIBRARY_ENTRY_POINT)
0382                 {
0383                     stateReturnValue = NVTX_EXTENSION_DISABLED;
0384                 }
0385                 NVTX_ERR("Failed to load injection library.\n");
0386             }
0387         }
0388 
0389         if (init_fnptr != NVTX_NULLPTR)
0390         {
0391             /* Invoke injection library's initialization function. If it returns
0392                0 (failure) and a dynamic injection was loaded, unload it. */
0393             entryPointStatus = init_fnptr(moduleInfo);
0394             if (entryPointStatus == 0)
0395             {
0396                 stateReturnValue = NVTX_EXTENSION_INIT_FN_FAILED;
0397                 NVTX_ERR("Failed to initialize injection library -- initialization function returned 0\n");
0398             }
0399         }
0400 
0401         /* Clean up any functions that are still uninitialized so that they are
0402            skipped. Set all to null if injection init function failed as well. */
0403         forceAllToNoops = (init_fnptr == NVTX_NULLPTR) || (entryPointStatus == 0);
0404         for (s = 0; s < moduleInfo->segmentsCount; ++s)
0405         {
0406             nvtxExtModuleSegment_t* segment = moduleInfo->segments + s;
0407             size_t i;
0408             for (i = 0; i < segment->slotCount; ++i)
0409             {
0410                 if (forceAllToNoops || (segment->functionSlots[i] == NVTX_EXTENSION_FRESH))
0411                 {
0412                     segment->functionSlots[i] = NVTX_EXTENSION_DISABLED;
0413                 }
0414             }
0415         }
0416 
0417         NVTX_MEMBAR();
0418 
0419         /* Signal that initialization has finished and the function pointers are set. */
0420         NVTX_ATOMIC_WRITE_PTR(moduleState, stateReturnValue);
0421     }
0422     else /* Spin-wait until initialization has finished. */
0423     {
0424         NVTX_MEMBAR();
0425         while (*moduleState != NVTX_EXTENSION_LOADED &&
0426                *moduleState != NVTX_EXTENSION_DISABLED &&
0427                *moduleState != NVTX_EXTENSION_INIT_FN_FAILED)
0428         {
0429             NVTX_YIELD();
0430             NVTX_MEMBAR();
0431         }
0432     }
0433 }
0434 
0435 #ifdef __cplusplus
0436 }
0437 #endif /* __cplusplus */