@@ -309,25 +309,26 @@ ur_adapter_handle_t_::ur_adapter_handle_t_()
309309
310310 if (UrL0Debug & UR_L0_DEBUG_BASIC) {
311311 logger.setLegacySink (std::make_unique<ur_legacy_sink>());
312- #ifdef UR_ADAPTER_LEVEL_ZERO_V2
313- setEnvVar (" ZEL_ENABLE_LOADER_LOGGING" , " 1" );
314- setEnvVar (" ZEL_LOADER_LOGGING_LEVEL" , " trace" );
315- setEnvVar (" ZEL_LOADER_LOG_CONSOLE" , " 1" );
316- setEnvVar (" ZE_ENABLE_VALIDATION_LAYER" , " 1" );
317- #endif
318312 };
319313
320314 if (UrL0Debug & UR_L0_DEBUG_VALIDATION) {
321315 setEnvVar (" ZE_ENABLE_VALIDATION_LAYER" , " 1" );
322316 setEnvVar (" ZE_ENABLE_PARAMETER_VALIDATION" , " 1" );
323317 }
324318
325- if (UrL0LeaksDebug) {
326- setEnvVar (" ZE_ENABLE_VALIDATION_LAYER" , " 1" );
327- setEnvVar (" ZEL_ENABLE_BASIC_LEAK_CHECKER" , " 1" );
328- }
329-
330319 PlatformCache.Compute = [](Result<PlatformVec> &result) {
320+ static std::once_flag ZeCallCountInitialized;
321+ try {
322+ std::call_once (ZeCallCountInitialized, []() {
323+ if (UrL0LeaksDebug) {
324+ ZeCallCount = new std::map<std::string, int >;
325+ }
326+ });
327+ } catch (...) {
328+ result = exceptionToResult (std::current_exception ());
329+ return ;
330+ }
331+
331332 uint32_t UserForcedSysManInit = 0 ;
332333 // Check if the user has disabled the default L0 Env initialization.
333334 const int UrSysManEnvInitEnabled = [&UserForcedSysManInit] {
@@ -418,17 +419,6 @@ ur_adapter_handle_t_::ur_adapter_handle_t_()
418419 loader_version.patch >= 2 )) {
419420 useInitDrivers = true ;
420421 }
421-
422- #ifdef UR_ADAPTER_LEVEL_ZERO_V2
423- if ((loader_version.major == 1 && loader_version.minor < 21 ) ||
424- (loader_version.major == 1 && loader_version.minor == 21 &&
425- loader_version.patch < 2 )) {
426- UR_LOG (
427- WARN,
428- " WARNING: Level Zero Loader version is older than 1.21.2. "
429- " Please update to the latest version for API logging support.\n " );
430- }
431- #endif
432422 }
433423
434424 if (useInitDrivers) {
@@ -545,6 +535,97 @@ void globalAdapterOnDemandCleanup() {
545535}
546536
547537ur_result_t adapterStateTeardown () {
538+ // Print the balance of various create/destroy native calls.
539+ // The idea is to verify if the number of create(+) and destroy(-) calls are
540+ // matched.
541+ if (ZeCallCount && (UrL0LeaksDebug) != 0 ) {
542+ bool LeakFound = false ;
543+ // clang-format off
544+ //
545+ // The format of this table is such that each row accounts for a
546+ // specific type of objects, and all elements in the raw except the last
547+ // one are allocating objects of that type, while the last element is known
548+ // to deallocate objects of that type.
549+ //
550+ std::vector<std::vector<std::string>> CreateDestroySet = {
551+ {" zeContextCreate" , " zeContextDestroy" },
552+ {" zeCommandQueueCreate" , " zeCommandQueueDestroy" },
553+ {" zeModuleCreate" , " zeModuleDestroy" },
554+ {" zeKernelCreate" , " zeKernelDestroy" },
555+ {" zeEventPoolCreate" , " zeEventPoolDestroy" },
556+ {" zeCommandListCreateImmediate" , " zeCommandListCreate" , " zeCommandListDestroy" },
557+ {" zeEventCreate" , " zeEventDestroy" },
558+ {" zeFenceCreate" , " zeFenceDestroy" },
559+ {" zeImageCreate" ," zeImageViewCreateExt" , " zeImageDestroy" },
560+ {" zeSamplerCreate" , " zeSamplerDestroy" },
561+ {" zeMemAllocDevice" , " zeMemAllocHost" , " zeMemAllocShared" , " zeMemFree" },
562+ };
563+
564+ // A sample output aimed below is this:
565+ // ------------------------------------------------------------------------
566+ // zeContextCreate = 1 \---> zeContextDestroy = 1
567+ // zeCommandQueueCreate = 1 \---> zeCommandQueueDestroy = 1
568+ // zeModuleCreate = 1 \---> zeModuleDestroy = 1
569+ // zeKernelCreate = 1 \---> zeKernelDestroy = 1
570+ // zeEventPoolCreate = 1 \---> zeEventPoolDestroy = 1
571+ // zeCommandListCreateImmediate = 1 |
572+ // zeCommandListCreate = 1 \---> zeCommandListDestroy = 1 ---> LEAK = 1
573+ // zeEventCreate = 2 \---> zeEventDestroy = 2
574+ // zeFenceCreate = 1 \---> zeFenceDestroy = 1
575+ // zeImageCreate = 0 \---> zeImageDestroy = 0
576+ // zeSamplerCreate = 0 \---> zeSamplerDestroy = 0
577+ // zeMemAllocDevice = 0 |
578+ // zeMemAllocHost = 1 |
579+ // zeMemAllocShared = 0 \---> zeMemFree = 1
580+ //
581+ // clang-format on
582+ // TODO: use logger to print this messages
583+ std::cerr << " Check balance of create/destroy calls\n " ;
584+ std::cerr << " ----------------------------------------------------------\n " ;
585+ std::stringstream ss;
586+ for (const auto &Row : CreateDestroySet) {
587+ int diff = 0 ;
588+ for (auto I = Row.begin (); I != Row.end ();) {
589+ const char *ZeName = (*I).c_str ();
590+ const auto &ZeCount = (*ZeCallCount)[*I];
591+
592+ bool First = (I == Row.begin ());
593+ bool Last = (++I == Row.end ());
594+
595+ if (Last) {
596+ ss << " \\ --->" ;
597+ diff -= ZeCount;
598+ } else {
599+ diff += ZeCount;
600+ if (!First) {
601+ ss << " | " ;
602+ std::cerr << ss.str () << " \n " ;
603+ ss.str (" " );
604+ ss.clear ();
605+ }
606+ }
607+ ss << std::setw (30 ) << std::right << ZeName;
608+ ss << " = " ;
609+ ss << std::setw (5 ) << std::left << ZeCount;
610+ }
611+
612+ if (diff) {
613+ LeakFound = true ;
614+ ss << " ---> LEAK = " << diff;
615+ }
616+
617+ std::cerr << ss.str () << ' \n ' ;
618+ ss.str (" " );
619+ ss.clear ();
620+ }
621+
622+ ZeCallCount->clear ();
623+ delete ZeCallCount;
624+ ZeCallCount = nullptr ;
625+ if (LeakFound)
626+ return UR_RESULT_ERROR_INVALID_MEM_OBJECT;
627+ }
628+
548629 // Due to multiple DLLMain definitions with SYCL, register to cleanup the
549630 // Global Adapter after refcnt is 0
550631#if defined(_WIN32)
0 commit comments