1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ===========================================================================
5 // File: MultiCoreJITPlayer.cpp
8 // ===========================================================================
9 // This file contains the implementation for MultiCore JIT profile playing back
10 // ===========================================================================
16 #include "dllimport.h"
17 #include "comdelegate.h"
18 #include "dbginterface.h"
20 #include "eventtrace.h"
26 #include "appdomain.hpp"
28 #include "multicorejit.h"
29 #include "multicorejitimpl.h"
31 // Options for controlling multicore JIT
33 unsigned g_MulticoreJitDelay = 0; // Delay in StartProfile
35 bool g_MulticoreJitEnabled = true; // Enable/Disable feature
37 ///////////////////////////////////////////////////////////////////////////////////
39 // class MulticoreJitCodeStorage
41 ///////////////////////////////////////////////////////////////////////////////////
44 void MulticoreJitCodeStorage::Init()
49 MODE_ANY; // called from BaseDomain::Init which is MODE_ANY
55 m_crstCodeMap.Init(CrstMulticoreJitHash);
60 MulticoreJitCodeStorage::~MulticoreJitCodeStorage()
62 LIMITED_METHOD_CONTRACT;
64 m_crstCodeMap.Destroy();
68 // Callback from MakeJitWorker to store compiled code, under MethodDesc lock
69 void MulticoreJitCodeStorage::StoreMethodCode(MethodDesc * pMD, PCODE pCode)
73 #ifdef PROFILING_SUPPORTED
74 if (CORProfilerTrackJITInfo())
82 CrstHolder holder(& m_crstCodeMap);
84 #ifdef MULTICOREJIT_LOGGING
85 if (Logging2On(LF2_MULTICOREJIT, LL_INFO1000))
87 MulticoreJitTrace(("%p %p StoredMethodCode", pMD, pCode));
93 if (! m_nativeCodeMap.Lookup(pMD, & code))
95 m_nativeCodeMap.Add(pMD, pCode);
103 // Query from MakeJitWorker: Lookup stored JITted methods
104 PCODE MulticoreJitCodeStorage::QueryMethodCode(MethodDesc * pMethod, BOOL shouldRemoveCode)
106 STANDARD_VM_CONTRACT;
110 if (m_nStored > m_nReturned) // Quick check before taking lock
112 CrstHolder holder(& m_crstCodeMap);
114 if (m_nativeCodeMap.Lookup(pMethod, & code) && shouldRemoveCode)
118 // Remove it to keep storage small (hopefully flat)
119 m_nativeCodeMap.Remove(pMethod);
123 #ifdef MULTICOREJIT_LOGGING
124 if (Logging2On(LF2_MULTICOREJIT, LL_INFO1000))
126 MulticoreJitTrace(("%p %p QueryMethodCode", pMethod, code));
134 ///////////////////////////////////////////////////////////////////////////////////
136 // class PlayerModuleInfo
138 ///////////////////////////////////////////////////////////////////////////////////
140 // Per module information kept for mapping to Module object
142 class PlayerModuleInfo
146 const ModuleRecord * m_pRecord;
154 LIMITED_METHOD_CONTRACT;
163 bool MeetLevel(FileLoadLevel level) const
165 LIMITED_METHOD_CONTRACT;
167 return (m_pModule != NULL) && (m_curLevel >= (int) level);
170 bool IsModuleLoaded() const
172 LIMITED_METHOD_CONTRACT;
174 return m_pModule != NULL;
177 bool LoadOkay() const
179 LIMITED_METHOD_CONTRACT;
181 return (m_pRecord->flags & FLAG_LOADOKAY) != 0;
184 // UpdateNeedLevel called
185 bool IsDependency() const
187 LIMITED_METHOD_CONTRACT;
189 return m_needLevel > -1;
192 bool IsLowerLevel() const
194 LIMITED_METHOD_CONTRACT;
196 return m_curLevel < m_needLevel;
199 // If module is loaded, lower then needed level, update its level
200 void UpdateCurrentLevel()
209 if (m_pModule != NULL)
211 if (m_curLevel < m_needLevel)
213 m_curLevel = (int) MulticoreJitManager::GetModuleFileLoadLevel(m_pModule);
218 bool UpdateNeedLevel(FileLoadLevel level)
220 LIMITED_METHOD_CONTRACT;
222 if (m_needLevel < (int) level)
224 m_needLevel = (int) level;
232 bool MatchWith(ModuleVersion & version, bool & gotVersion, Module * pModule, bool & shortAbort, bool fAppx);
234 #ifdef MULTICOREJIT_LOGGING
235 void Dump(const wchar_t * prefix, int index);
241 bool PlayerModuleInfo::MatchWith(ModuleVersion & version, bool & gotVersion, Module * pModule, bool & shortAbort, bool fAppx)
243 STANDARD_VM_CONTRACT;
245 if ((m_pModule == NULL) && m_pRecord->MatchWithModule(version, gotVersion, pModule, shortAbort, fAppx))
248 m_curLevel = (int) MulticoreJitManager::GetModuleFileLoadLevel(pModule);
250 if (m_pRecord->jitMethodCount == 0)
252 m_enableJit = false; // No method to JIT for this module, not really needed; just to be correct
254 else if (CORDebuggerEnCMode(pModule->GetDebuggerInfoBits()))
257 MulticoreJitTrace(("Jit disable for module due to EnC"));
258 _FireEtwMulticoreJit(W("FILTERMETHOD-EnC"), W(""), 0, 0, 0);
268 #ifdef MULTICOREJIT_LOGGING
270 void PlayerModuleInfo::Dump(const wchar_t * prefix, int index)
275 if (!Logging2On(LF2_MULTICOREJIT, LL_INFO100))
283 ssBuff.Append(prefix);
284 ssBuff.AppendPrintf(W("[%2d]: "), index);
286 const ModuleVersion & ver = m_pRecord->version;
288 ssBuff.AppendPrintf(W(" %d.%d.%05d.%04d.%d level %2d, need %2d"), ver.major, ver.minor, ver.build, ver.revision, ver.versionFlags, m_curLevel, m_needLevel);
290 ssBuff.AppendPrintf(W(" pModule: %p "), m_pModule);
294 for (i = 0; i < m_pRecord->ModuleNameLen(); i ++)
296 ssBuff.Append((wchar_t) m_pRecord->GetModuleName()[i]);
305 MulticoreJitTrace(("%S", ssBuff.GetUnicode()));
312 ///////////////////////////////////////////////////////////////////////////////////
314 // MulticoreJitProfilePlayer
316 ///////////////////////////////////////////////////////////////////////////////////
318 const unsigned EmptyToken = 0xFFFFFFFF;
320 bool ModuleRecord::MatchWithModule(ModuleVersion & modVersion, bool & gotVersion, Module * pModule, bool & shouldAbort, bool fAppx) const
322 STANDARD_VM_CONTRACT;
324 LPCUTF8 pModuleName = pModule->GetSimpleName();
325 const char * pName = GetModuleName();
327 size_t len = strlen(pModuleName);
329 if ((len == lenModuleName) && (memcmp(pModuleName, pName, lenModuleName) == 0))
331 // Ignore version check on play back when running under Appx (also GetModuleVersion is expensive)
333 // For Appx, multicore JIT profile is pre-generated by application vendor, installed together with the package.
334 // So it may not have exact match with its own assemblies, and assemblies installed on the system.
340 if (! gotVersion) // Calling expensive GetModuleVersion only when simple name matches
344 if (! modVersion.GetModuleVersion(pModule))
350 if (version.MatchWith(modVersion))
352 // If matching image with different native image flag is detected, mark and abort playing profile back
353 if (version.NativeImageFlagDiff(modVersion))
355 MulticoreJitTrace((" Module with different native image flag: %s", pName));
368 MulticoreJitProfilePlayer::MulticoreJitProfilePlayer(ICLRPrivBinder * pBinderContext, LONG nSession, bool fAppxMode)
369 : m_stats(::GetAppDomain()->GetMulticoreJitManager().GetStats()), m_appdomainSession(::GetAppDomain()->GetMulticoreJitManager().GetProfileSession())
371 LIMITED_METHOD_CONTRACT;
373 m_pBinderContext = pBinderContext;
374 m_nMySession = nSession;
376 m_headerModuleCount = 0;
378 m_nBlockingCount = 0;
379 m_nMissingModule = 0;
380 m_nLoadedModuleCount = 0;
381 m_shouldAbort = false;
382 m_fAppxMode = fAppxMode;
385 m_pFileBuffer = NULL;
388 m_busyWith = EmptyToken;
390 m_nStartTime = GetTickCount();
394 MulticoreJitProfilePlayer::~MulticoreJitProfilePlayer()
396 LIMITED_METHOD_CONTRACT;
398 if (m_pModules != NULL)
400 delete [] m_pModules;
404 if (m_pFileBuffer != NULL)
406 delete [] m_pFileBuffer;
412 bool MulticoreJitManager::ModuleHasNoCode(Module * pModule)
414 LIMITED_METHOD_CONTRACT;
416 if (pModule->IsResource())
421 IMDInternalImport * pImport = pModule->GetMDImport();
425 if ((pImport->GetCountWithTokenKind(mdtTypeDef) == 0) &&
426 (pImport->GetCountWithTokenKind(mdtMethodDef) == 0) &&
427 (pImport->GetCountWithTokenKind(mdtFieldDef) == 0)
438 // We only support default load context, non dynamic module, non domain neutral (needed for dependency)
439 bool MulticoreJitManager::IsSupportedModule(Module * pModule, bool fMethodJit, bool fAppx)
454 PEFile * pFile = pModule->GetFile();
457 if (pFile->IsDynamic()) // Ignore dynamic modules
462 if (pFile->GetPath().IsEmpty()) // Ignore in-memory modules
470 if (ModuleHasNoCode(pModule))
476 Assembly * pAssembly = pModule->GetAssembly();
484 // ModuleRecord handling: add to m_ModuleList
486 HRESULT MulticoreJitProfilePlayer::HandleModuleRecord(const ModuleRecord * pMod)
488 STANDARD_VM_CONTRACT;
492 PlayerModuleInfo & info = m_pModules[m_moduleCount];
494 info.m_pModule = NULL;
495 info.m_pRecord = pMod;
497 #ifdef MULTICOREJIT_LOGGING
498 info.Dump(W("ModuleRecord"), m_moduleCount);
507 #ifndef DACCESS_COMPILE
508 class MulticoreJitPrepareCodeConfig : public PrepareCodeConfig
511 MulticoreJitPrepareCodeConfig(MethodDesc* pMethod) :
512 PrepareCodeConfig(NativeCodeVersion(pMethod), FALSE, FALSE)
515 virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse)
517 MulticoreJitManager & mcJitManager = GetAppDomain()->GetMulticoreJitManager();
518 mcJitManager.GetMulticoreJitCodeStorage().StoreMethodCode(GetMethodDesc(), pCode);
524 // Call JIT to compile a method
526 bool MulticoreJitProfilePlayer::CompileMethodDesc(Module * pModule, MethodDesc * pMD)
528 STANDARD_VM_CONTRACT;
530 COR_ILMETHOD_DECODER::DecoderStatus status;
532 COR_ILMETHOD_DECODER header(pMD->GetILHeader(), pModule->GetMDImport(), & status);
534 if (status == COR_ILMETHOD_DECODER::SUCCESS)
536 if (m_stats.m_nTryCompiling == 0)
538 MulticoreJitTrace(("First call to MakeJitWorker"));
541 m_stats.m_nTryCompiling ++;
543 // Reset the flag to allow managed code to be called in multicore JIT background thread from this routine
544 ThreadStateNCStackHolder holder(-1, Thread::TSNC_CallingManagedCodeDisabled);
546 // PrepareCode calls back to MulticoreJitCodeStorage::StoreMethodCode under MethodDesc lock
547 MulticoreJitPrepareCodeConfig config(pMD);
548 pMD->PrepareCode(&config);
557 // Conditional JIT of a method
558 void MulticoreJitProfilePlayer::JITMethod(Module * pModule, unsigned methodIndex)
560 STANDARD_VM_CONTRACT;
562 // Ensure non-null module
565 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_PRIVATEMULTICOREJIT_KEYWORD))
567 _FireEtwMulticoreJitA(W("NULLMODULEPOINTER"), NULL, methodIndex, 0, 0);
572 methodIndex &= METHODINDEX_MASK; // 20-bit
574 unsigned token = TokenFromRid(methodIndex, mdtMethodDef);
576 // Similar to Module::FindMethod + Module::FindMethodThrowing,
577 // except it calls GetMethodDescFromMemberDefOrRefOrSpec with strictMetadataChecks=FALSE to allow generic instantiation
578 MethodDesc * pMethod = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, token, NULL, FALSE, FALSE);
580 if ((pMethod != NULL) && ! pMethod->IsDynamicMethod() && pMethod->HasILHeader())
582 // MethodDesc::FindOrCreateTypicalSharedInstantiation is expensive, avoid calling it unless the method or class has generic arguments
583 if (pMethod->HasClassOrMethodInstantiation())
585 pMethod = pMethod->FindOrCreateTypicalSharedInstantiation();
592 pModule = pMethod->GetModule_NoLogging();
595 if (pMethod->GetNativeCode() != NULL) // last check before
597 m_stats.m_nHasNativeCode ++;
603 m_busyWith = methodIndex;
605 bool rslt = CompileMethodDesc(pModule, pMethod);
607 m_busyWith = EmptyToken;
618 m_stats.m_nFilteredMethods ++;
620 MulticoreJitTrace(("Filtered out methods: pModule:[%s] token:[%x]", pModule->GetSimpleName(), token));
622 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_PRIVATEMULTICOREJIT_KEYWORD))
624 _FireEtwMulticoreJitA(W("FILTERMETHOD-GENERIC"), pModule->GetSimpleName(), token, 0, 0);
629 class MulticoreJitPlayerModuleEnumerator : public MulticoreJitModuleEnumerator
631 MulticoreJitProfilePlayer * m_pPlayer;
633 // Implementation of MulticoreJitModuleEnumerator::OnModule
634 HRESULT OnModule(Module * pModule)
645 return m_pPlayer->OnModule(pModule);
650 MulticoreJitPlayerModuleEnumerator(MulticoreJitProfilePlayer * pPlayer)
657 HRESULT MulticoreJitProfilePlayer::OnModule(Module * pModule)
659 STANDARD_VM_CONTRACT;
663 // Check if already matched
664 for (unsigned i = 0; i < m_moduleCount; i ++)
666 if (m_pModules[i].m_pModule == pModule)
672 ModuleVersion version; // GetModuleVersion is called on-demand when simple names matches
674 bool gotVersion = false;
676 // Match with simple name, and then version/flag/guid
677 for (unsigned i = 0; i < m_moduleCount; i ++)
679 if (m_pModules[i].MatchWith(version, gotVersion, pModule, m_shouldAbort, m_fAppxMode))
681 m_nLoadedModuleCount ++;
690 HRESULT MulticoreJitProfilePlayer::UpdateModuleInfo()
692 STANDARD_VM_CONTRACT;
696 MulticoreJitTrace(("UpdateModuleInfo"));
698 // Enumerate module if there is a module needed, but not loaded yet
699 for (unsigned i = 0; i < m_moduleCount; i ++)
701 PlayerModuleInfo & info = m_pModules[i];
703 if (! info.LoadOkay() && info.IsDependency() && ! info.IsModuleLoaded())
705 MulticoreJitTrace((" Enumerate modules for player"));
707 MulticoreJitPlayerModuleEnumerator enumerator(this);
709 enumerator.EnumerateLoadedModules(GetAppDomain()); // Enumerate modules, hope to find new matches
715 // Update load level, re-calculate blocking count
716 m_nBlockingCount = 0;
717 m_nMissingModule = 0;
725 // Check for blocking level
726 for (unsigned i = 0; i < m_moduleCount; i ++)
728 PlayerModuleInfo & info = m_pModules[i];
730 if (! info.LoadOkay() && info.IsLowerLevel())
732 if (info.IsModuleLoaded())
734 info.UpdateCurrentLevel();
741 if (info.IsLowerLevel())
743 #ifdef MULTICOREJIT_LOGGING
744 info.Dump(W(" BlockingModule"), i);
747 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_PRIVATEMULTICOREJIT_KEYWORD))
749 _FireEtwMulticoreJitA(W("BLOCKINGMODULE"), info.m_pRecord->GetModuleName(), i, info.m_curLevel, info.m_needLevel);
758 MulticoreJitTrace(("Blocking count: %d, missing module: %d, hr=%x", m_nBlockingCount, m_nMissingModule, hr));
764 bool MulticoreJitProfilePlayer::ShouldAbort(bool fast) const
766 LIMITED_METHOD_CONTRACT;
768 if (m_nMySession != m_appdomainSession.GetValue())
770 MulticoreJitTrace(("MulticoreJitProfilePlayer::ShouldAbort session over"));
771 _FireEtwMulticoreJit(W("ABORTPLAYER"), W("Session over"), 0, 0, 0);
780 if (GetTickCount() - m_nStartTime > MULTICOREJITLIFE)
782 MulticoreJitTrace(("MulticoreJitProfilePlayer::ShouldAbort time over"));
784 _FireEtwMulticoreJit(W("ABORTPLAYER"), W("Time out"), 0, 0, 0);
794 const int DelayUnit = 1; // 1 ms delay
795 const int MissingModuleDelay = 10; // 10 ms for each missing module
798 // Wait for all the module loading and level requests to be fullfilled
799 // This allows for longer delay based on number of mismatches, to reduce CPU usage
801 // Return true blocking count is 0, false if aborted
802 bool MulticoreJitProfilePlayer::GroupWaitForModuleLoad(int pos)
804 STANDARD_VM_CONTRACT;
806 MulticoreJitTrace(("Enter GroupWaitForModuleLoad(pos=%4d): %d modules loaded, blocking count=%d", pos, m_nLoadedModuleCount, m_nBlockingCount));
808 _FireEtwMulticoreJit(W("GROUPWAIT"), W("Enter"), m_nLoadedModuleCount, m_nBlockingCount, pos);
812 // Ensure that we don't block in this particular case for longer than the block limit.
813 // This limit is smaller than the overall MULTICOREJITLIFE and ensures that we don't sit for the
814 // full player lifetime waiting for a module when the app behavior has changed.
815 DWORD currentModuleBlockStart = GetTickCount();
817 // Only allow module blocking to occur a certain number of times.
819 while (! ShouldAbort(false))
821 if (FAILED(UpdateModuleInfo()))
826 if (m_nBlockingCount == 0)
832 if(GetTickCount() - currentModuleBlockStart > MULTICOREJITBLOCKLIMIT)
834 MulticoreJitTrace(("MulticoreJitProfilePlayer::GroupWaitForModuleLoad timeout exceeded."));
835 _FireEtwMulticoreJit(W("ABORTPLAYER"), W("GroupWaitForModuleLoad timeout exceeded."), 0, 0, 0);
840 // Heuristic for reducing CPU usage: delay longer when there are more blocking modules
841 unsigned delay = min((m_nMissingModule * MissingModuleDelay + m_nBlockingCount) * DelayUnit, 50);
843 MulticoreJitTrace(("Delay: %d ms", delay));
845 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context, TRACE_LEVEL_VERBOSE, CLR_PRIVATEMULTICOREJIT_KEYWORD))
847 _FireEtwMulticoreJit(W("GROUPWAIT"), W("Delay"), delay, 0, 0);
850 ClrSleepEx(delay, FALSE);
852 m_stats.m_nTotalDelay += (unsigned short) delay;
853 m_stats.m_nDelayCount ++;
856 MulticoreJitTrace(("Leave GroupWaitForModuleLoad(pos=%4d): blocking count=%d (rslt=%d)", pos, m_nBlockingCount, rslt));
858 _FireEtwMulticoreJit(W("GROUPWAIT"), W("Leave"), m_nLoadedModuleCount, m_nBlockingCount, rslt);
864 bool MulticoreJitProfilePlayer::HandleModuleDependency(unsigned jitInfo)
866 STANDARD_VM_CONTRACT;
868 // depends on moduleTo, which may not loaded yet
870 unsigned moduleTo = jitInfo & MODULE_MASK;
872 if (moduleTo < m_moduleCount)
874 unsigned level = (jitInfo >> LEVEL_SHIFT) & LEVEL_MASK;
876 PlayerModuleInfo & mod = m_pModules[moduleTo];
878 // Load the module if necessary.
881 // Update loaded module status.
882 AppDomain * pAppDomain = GetAppDomain();
883 _ASSERTE(pAppDomain != NULL);
885 MulticoreJitPlayerModuleEnumerator moduleEnumerator(this);
886 moduleEnumerator.EnumerateLoadedModules(pAppDomain);
890 // Get the assembly name.
891 SString assemblyName;
892 assemblyName.SetASCII(mod.m_pRecord->GetAssemblyName(), mod.m_pRecord->AssemblyNameLen());
894 // Load the assembly.
895 DomainAssembly * pDomainAssembly = LoadAssembly(assemblyName);
899 // If we successfully loaded the assembly, enumerate the modules in the assembly
900 // and update all modules status.
901 moduleEnumerator.HandleAssembly(pDomainAssembly);
903 if (mod.m_pModule == NULL)
905 // Unable to load the assembly, so abort.
911 // Unable to load the assembly, so abort.
917 if (mod.UpdateNeedLevel((FileLoadLevel) level))
919 if (! mod.LoadOkay()) // allow first part WinMD to load in background thread
929 DomainAssembly * MulticoreJitProfilePlayer::LoadAssembly(SString & assemblyName)
931 STANDARD_VM_CONTRACT;
933 // Get the assembly name.
934 StackScratchBuffer scratch;
935 const ANSI* pAnsiAssemblyName = assemblyName.GetANSI(scratch);
939 // Initialize the assembly spec.
940 HRESULT hr = spec.Init(pAnsiAssemblyName);
946 // Set the binding context to the assembly load context.
947 if (m_pBinderContext != NULL)
949 spec.SetBindingContext(m_pBinderContext);
952 // Bind and load the assembly.
953 return spec.LoadDomainAssembly(
955 FALSE); // Don't throw on FileNotFound.
959 inline bool MethodJifInfo(unsigned inst)
961 LIMITED_METHOD_CONTRACT;
963 return ((inst & MODULE_DEPENDENCY) == 0);
967 // Process a block of methodDef, call JIT if not blocked
968 HRESULT MulticoreJitProfilePlayer::HandleMethodRecord(unsigned * buffer, int count)
970 STANDARD_VM_CONTRACT;
972 HRESULT hr = E_ABORT;
974 MulticoreJitTrace(("MethodRecord(%d) start %d methods, %d mod loaded", m_stats.m_nTotalMethod, count, m_nLoadedModuleCount));
976 MulticoreJitManager & manager = GetAppDomain()->GetMulticoreJitManager();
978 #ifdef MULTICOREJIT_LOGGING
980 MulticoreJitCodeStorage & curStorage = manager.GetMulticoreJitCodeStorage();
982 int lastCompiled = curStorage.GetStored();
988 while (! ShouldAbort(true) && (pos < count))
990 unsigned jitInfo = buffer[pos]; // moduleIndex + methodIndex
992 unsigned moduleIndex = jitInfo >> 24;
994 if (moduleIndex < m_moduleCount)
996 if (jitInfo & MODULE_DEPENDENCY) // Module depedency information
998 if (! HandleModuleDependency(jitInfo))
1005 PlayerModuleInfo & info = m_pModules[moduleIndex];
1007 m_stats.m_nTotalMethod ++;
1009 // If module is disabled for Jitting, just skip method without even waiting
1010 if (! info.m_enableJit)
1012 m_stats.m_nFilteredMethods ++;
1017 // To reduce contention with foreground thread, walk backward within the group of methods Jittable methods, not broken apart by dependency
1019 int run = 1; // size of the group
1021 while (((pos + run) < count) && MethodJifInfo(buffer[pos + run]))
1025 // If walk-back run is too long, lots of methods in the front will be missed by background thread
1026 if (run > MAX_WALKBACK)
1034 MulticoreJitTrace(("Jit backwards %d methods", run));
1037 // Walk backwards within the same group, may be from different modules
1038 for (int p = pos + run - 1; p >= pos; p --)
1040 unsigned inst = buffer[p];
1042 _ASSERTE(MethodJifInfo(inst));
1044 PlayerModuleInfo & mod = m_pModules[inst >> 24];
1046 _ASSERTE(mod.IsModuleLoaded());
1048 if (mod.m_enableJit)
1050 JITMethod(mod.m_pModule, inst);
1054 m_stats.m_nFilteredMethods ++;
1058 m_stats.m_nWalkBack += (short) (run - 1);
1059 m_stats.m_nTotalMethod += (short) (run - 1);
1061 pos += run - 1; // Skip the group
1068 hr = COR_E_BADIMAGEFORMAT;
1080 m_stats.m_nMissingModuleSkip += (short) (count - pos);
1082 MulticoreJitTrace(("MethodRecord(%d) end %d compiled, %d aborted / %d methods, hr=%x",
1083 m_stats.m_nTotalMethod,
1084 curStorage.GetStored() - lastCompiled,
1085 count - pos, count, hr));
1093 void MulticoreJitProfilePlayer::TraceSummary()
1095 LIMITED_METHOD_CONTRACT;
1097 MulticoreJitCodeStorage & curStorage = GetAppDomain()->GetMulticoreJitManager().GetMulticoreJitCodeStorage();
1099 unsigned returned = curStorage.GetReturned();
1101 #ifdef MULTICOREJIT_LOGGING
1103 unsigned compiled = curStorage.GetStored();
1105 MulticoreJitTrace(("PlayerSummary: %d total: %d no mod, %d filtered out, %d had code, %d other, %d tried, %d compiled, %d returned, %d%% efficiency, %d mod loaded, %d ms delay(%d)",
1106 m_stats.m_nTotalMethod,
1107 m_stats.m_nMissingModuleSkip,
1108 m_stats.m_nFilteredMethods,
1109 m_stats.m_nHasNativeCode,
1110 m_stats.m_nTotalMethod - m_stats.m_nMissingModuleSkip - m_stats.m_nFilteredMethods - m_stats.m_nHasNativeCode - m_stats.m_nTryCompiling,
1111 m_stats.m_nTryCompiling,
1114 (m_stats.m_nTotalMethod == 0) ? 100 : returned * 100 / m_stats.m_nTotalMethod,
1115 m_nLoadedModuleCount,
1116 m_stats.m_nTotalDelay,
1117 m_stats.m_nDelayCount
1122 _FireEtwMulticoreJit(W("PLAYERSUMMARY"), W(""), m_stats.m_nTryCompiling, m_stats.m_nHasNativeCode, returned);
1126 HRESULT MulticoreJitProfilePlayer::ReadCheckFile(const wchar_t * pFileName)
1138 HANDLE hFile = WszCreateFile(pFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1140 if (hFile == INVALID_HANDLE_VALUE)
1142 return COR_E_FILENOTFOUND;
1145 HeaderRecord header;
1149 if (! ::ReadFile(hFile, & header, sizeof(header), &cbRead, NULL))
1151 hr = COR_E_BADIMAGEFORMAT;
1153 else if (cbRead != sizeof(header))
1155 hr = COR_E_BADIMAGEFORMAT;
1159 m_headerModuleCount = header.moduleCount;
1161 MulticoreJitTrace(("HeaderRecord(version=%d, module=%d, method=%d)", header.version, m_headerModuleCount, header.methodCount));
1163 if ((header.version != MULTICOREJIT_PROFILE_VERSION) || (header.moduleCount > MAX_MODULES) || (header.methodCount > MAX_METHOD_ARRAY) ||
1164 (header.recordID != Pack8_24(MULTICOREJIT_HEADER_RECORD_ID, sizeof(HeaderRecord))))
1166 hr = COR_E_BADIMAGEFORMAT;
1170 m_pModules = new (nothrow) PlayerModuleInfo[m_headerModuleCount];
1172 if (m_pModules == NULL)
1181 m_nFileSize = SafeGetFileSize(hFile, 0);
1183 if (m_nFileSize > sizeof(header))
1185 m_nFileSize -= sizeof(header);
1187 m_pFileBuffer = new (nothrow) BYTE[m_nFileSize];
1189 if (m_pFileBuffer == NULL)
1193 else if (::ReadFile(hFile, m_pFileBuffer, m_nFileSize, & cbRead, NULL))
1195 if (cbRead != m_nFileSize)
1197 hr = COR_E_BADIMAGEFORMAT;
1202 hr = CLDB_E_FILE_BADREAD;
1207 hr = COR_E_BADIMAGEFORMAT;
1213 _FireEtwMulticoreJit(W("PLAYER"), W("Header"), hr, m_headerModuleCount, header.methodCount);
1221 HRESULT MulticoreJitProfilePlayer::PlayProfile()
1223 STANDARD_VM_CONTRACT;
1227 DWORD start = GetTickCount();
1229 Thread * pThread = GetThread();
1232 // 1 marks background thread
1233 FireEtwThreadCreated((ULONGLONG) pThread, (ULONGLONG) GetAppDomain(), 1, pThread->GetThreadId(), pThread->GetOSThreadId(), GetClrInstanceId());
1236 const BYTE * pBuffer = m_pFileBuffer;
1238 unsigned nSize = m_nFileSize;
1240 MulticoreJitTrace(("PlayProfile %d bytes in (%s)",
1242 GetAppDomain()->GetFriendlyNameForLogging()));
1244 while ((SUCCEEDED(hr)) && (nSize > sizeof(unsigned)))
1246 unsigned data = * (const unsigned *) pBuffer;
1247 unsigned rcdLen = data & 0xFFFFFF;
1248 unsigned rcdTyp = data >> 24;
1250 if ((rcdLen > nSize) || (rcdLen & 3)) // Better DWORD align
1252 hr = COR_E_BADIMAGEFORMAT;
1256 if (rcdTyp == MULTICOREJIT_MODULE_RECORD_ID)
1258 const ModuleRecord * pRec = (const ModuleRecord * ) pBuffer;
1260 if (((unsigned)(pRec->lenModuleName
1261 + pRec->lenAssemblyName
1262 ) > (rcdLen - sizeof(ModuleRecord))) ||
1263 (m_moduleCount >= m_headerModuleCount))
1265 hr = COR_E_BADIMAGEFORMAT;
1269 hr = HandleModuleRecord(pRec);
1272 else if (rcdTyp == MULTICOREJIT_JITINF_RECORD_ID)
1274 int mCount = (rcdLen - sizeof(unsigned)) / sizeof(unsigned);
1276 hr = HandleMethodRecord((unsigned *) (pBuffer + sizeof(unsigned)), mCount);
1280 hr = COR_E_BADIMAGEFORMAT;
1287 if (SUCCEEDED(hr) && ShouldAbort(false))
1293 start = GetTickCount() - start;
1296 FireEtwThreadTerminated((ULONGLONG) pThread, (ULONGLONG) GetAppDomain(), GetClrInstanceId());
1299 MulticoreJitTrace(("Background thread running for %d ms, %d methods, hr=%x", start, m_stats.m_nTotalMethod, hr));
1307 HRESULT MulticoreJitProfilePlayer::JITThreadProc(Thread * pThread)
1314 INJECT_FAULT(COMPlusThrowOM(););
1318 m_stats.m_hr = S_OK;
1323 // Go into preemptive mode
1326 m_stats.m_hr = PlayProfile();
1331 if (SUCCEEDED(m_stats.m_hr))
1333 m_stats.m_hr = COR_E_EXCEPTION;
1336 EX_END_CATCH(SwallowAllExceptions);
1338 return (DWORD) m_stats.m_hr;
1342 DWORD WINAPI MulticoreJitProfilePlayer::StaticJITThreadProc(void *args)
1350 INJECT_FAULT(COMPlusThrowOM(););
1356 BEGIN_ENTRYPOINT_NOTHROW;
1358 MulticoreJitTrace(("StaticJITThreadProc starting"));
1360 // Mark the background thread via an ETW event for diagnostics.
1361 _FireEtwMulticoreJit(W("JITTHREAD"), W(""), 0, 0, 0);
1363 MulticoreJitProfilePlayer * pPlayer = (MulticoreJitProfilePlayer *) args;
1365 if (pPlayer != NULL)
1367 Thread * pThread = pPlayer->m_pThread;
1369 if ((pThread != NULL) && pThread->HasStarted())
1371 // Disable calling managed code in background thread
1372 ThreadStateNCStackHolder holder(TRUE, Thread::TSNC_CallingManagedCodeDisabled);
1374 // Run as background thread, so ThreadStore::WaitForOtherThreads will not wait for it
1375 pThread->SetBackground(TRUE);
1377 hr = pPlayer->JITThreadProc(pThread);
1380 // It needs to be deleted after GCX_PREEMP ends
1381 if (pThread != NULL)
1383 DestroyThread(pThread);
1386 // The background thread is reponsible for deleting the MulticoreJitProfilePlayer object once it's started
1387 // Actually after Thread::StartThread succeeds
1391 MulticoreJitTrace(("StaticJITThreadProc endding(%x)", hr));
1393 END_ENTRYPOINT_NOTHROW;
1399 HRESULT MulticoreJitProfilePlayer::ProcessProfile(const wchar_t * pFileName)
1401 STANDARD_VM_CONTRACT;
1403 HRESULT hr = ReadCheckFile(pFileName);
1407 _ASSERTE(m_pThread == NULL);
1409 m_pThread = SetupUnstartedThread();
1411 _ASSERTE(m_pThread != NULL);
1413 if (m_pThread->CreateNewThread(0, StaticJITThreadProc, this))
1415 int t = (int) m_pThread->StartThread();