diff options
Diffstat (limited to 'src/vm/multicorejitimpl.h')
-rw-r--r-- | src/vm/multicorejitimpl.h | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/src/vm/multicorejitimpl.h b/src/vm/multicorejitimpl.h new file mode 100644 index 0000000000..58a9df7827 --- /dev/null +++ b/src/vm/multicorejitimpl.h @@ -0,0 +1,497 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: MultiCoreJITImpl.h +// + +// +// Multicore JIT internal implementation header file +// +// ====================================================================================== + +#ifdef _DEBUG + +#define MULTICOREJIT_LOGGING + +#else +// Enable direct logging through OutputDebugMessage in ret build for perf investigation, to be disabled when checkin + +// #define MULTICOREJIT_LOGGING + +#endif + +// Make sure a record can fit within 2048 bytes, 511 methods now + +const int MAX_RECORD_SIZE = 2048; +const unsigned MAX_JIT_COUNT = (MAX_RECORD_SIZE - sizeof(unsigned)) / sizeof(unsigned); + +const int HEADER_W_COUNTER = 14; // Extra 16-bit counters in header for statistics: 28 +const int HEADER_D_COUNTER = 3; // Extra 32-bit counters in header for statistics: 12 +const unsigned MAX_MODULES = 512; // Maximum number of modules + +const unsigned MAX_METHOD_ARRAY = 16384; // Maximum number of methods + +const int MULTICOREJITLIFE = 60 * 1000; // 60 seconds + +const int MULTICOREJITBLOCKLIMIT = 10 * 1000; // 10 seconds + + // 8-bit module index + + // Method JIT information: 8-bit module 4-bit flag 20-bit method index +const unsigned MODULE_DEPENDENCY = 0x800000; // 1-bit module dependency mask +const unsigned JIT_BY_APP_THREAD = 0x400000; // 1-bit application thread + +const unsigned METHODINDEX_MASK = 0x0FFFFF; // 20-bit method index + + // Dependendy information: 8-bit module 4-bit flag 4-bit unused 8-bit level 8-bit module +const unsigned LEVEL_SHIFT = 8; +const unsigned LEVEL_MASK = 0xFF; // 8-bit file load level +const unsigned MODULE_MASK = 0xFF; // 8-bit dependent module index + +const int MAX_WALKBACK = 128; + +enum +{ + MULTICOREJIT_PROFILE_VERSION = 101, + + MULTICOREJIT_HEADER_RECORD_ID = 1, + MULTICOREJIT_MODULE_RECORD_ID = 2, + MULTICOREJIT_JITINF_RECORD_ID = 3 +}; + + +inline unsigned Pack8_24(unsigned up, unsigned low) +{ + LIMITED_METHOD_CONTRACT; + + return (up << 24) + low; +} + +// Multicore JIT profile format + +// <profile>::= <HeaderRecord> { <ModuleRecord> | <JitInfRecord> } +// +// 1. Each record is DWORD aligned +// 2. Each record starts with a DWORD <recordID> with Pack8_24(record type, record size) +// 3. Counter are just statistical information gathed (mainly during play back), good for quick diagnosis, not used to guide playback +// 4 Maximum number of modules supported is 256 +// 5 Simple module name stored +// 6 Maximum method index: 20-bit, could extend to 22 bits +// 7 JIT_BY_APP_THREAD is for diagnosis only + +// <HeaderRecord>::= <recordID> <version> <timeStamp> <moduleCount> <methodCount> <DependencyCount> <unsigned short counter>*14 <unsigned counter>*3 +// <ModuleRecord>::= <recordID> <ModuleVersion> <JitMethodCount> <loadLevel> <lenModuleName> char*lenModuleName <padding> +// <JifInfRecord>::= <recordID> { <moduleDependency> | <methodJitInfo> } + +// <moduleDependency>:: +// 8-bit source module index, current always 0 until we track per module dependency +// 8-bit flag MODULE_DEPENDENCY is 1 +// 8-bit load level +// 8-bit target module index + +// <methodJitInfo>:: +// 8-bit module index, current always 0 until we track per module dependency +// 4-bit flag MODULE_DEPENDENCY is 0, JIT_BY_APP_THREAD could be 1 +// 20-bit method index + + +struct HeaderRecord +{ + unsigned recordID; + unsigned version; + unsigned timeStamp; + unsigned moduleCount; + unsigned methodCount; + unsigned moduleDepCount; + unsigned short shortCounters[HEADER_W_COUNTER]; + unsigned longCounters [HEADER_D_COUNTER]; +}; + + +class ModuleVersion +{ +public: + unsigned short major; + unsigned short minor; + unsigned short build; + unsigned short revision; + + unsigned versionFlags :31; + unsigned hasNativeImage:1; + + GUID mvid; + + bool GetModuleVersion(Module * pModule); + + ModuleVersion() + { + LIMITED_METHOD_CONTRACT; + + memset(this, 0, sizeof(ModuleVersion)); + } + + bool MatchWith(const ModuleVersion & other) const + { + LIMITED_METHOD_CONTRACT; + + if ((major == other.major) && + (minor == other.minor) && + (build == other.build) && + (revision == other.revision) && + (versionFlags == other.versionFlags)) + { + return memcmp(& mvid, & other.mvid, sizeof(mvid)) == 0; + } + + return false; + } + + bool NativeImageFlagDiff(const ModuleVersion & other) const + { + LIMITED_METHOD_CONTRACT; + + return hasNativeImage != other.hasNativeImage; + } +}; + +inline unsigned RoundUp(unsigned val) +{ + LIMITED_METHOD_CONTRACT; + + return (val + 3) / 4 * 4; +} + +const unsigned short FLAG_LOADOKAY = 1; // Okay to load the module in background thread (e.g. for Appx first party WinMD) + +// Used to mark a module that was loaded in the LOADFROM context. +// First 16 bits are reserved for CorAssemblyFlags. Use the last bit (bit 31) to allow for expansion of CorAssemblyFlags. +const unsigned int VERSIONFLAG_LOADCTX_LOADFROM = 0x40000000; + +// Module record stored in the profile without the name + +class ModuleRecord +{ +public: + unsigned recordID; + ModuleVersion version; + unsigned short jitMethodCount; + unsigned short flags; + unsigned short wLoadLevel; + unsigned short lenModuleName; +#if defined(FEATURE_CORECLR) + unsigned short lenAssemblyName; +#endif + + ModuleRecord(unsigned lenName = 0, unsigned lenAssemblyName = 0); + + bool MatchWithModule(ModuleVersion & version, bool & gotVersion, Module * pModule, bool & shouldAbort, bool fAppx) const; + + unsigned ModuleNameLen() const + { + LIMITED_METHOD_CONTRACT; + + return lenModuleName; + } + + const char * GetModuleName() const + { + LIMITED_METHOD_CONTRACT; + + return (const char *) (this + 1); // after this record + } + +#if defined(FEATURE_CORECLR) + unsigned AssemblyNameLen() const + { + LIMITED_METHOD_CONTRACT; + + return lenAssemblyName; + } + + const char * GetAssemblyName() const + { + return GetModuleName() + RoundUp(lenModuleName); // after the module name + } +#endif + + void SetLoadLevel(FileLoadLevel loadLevel) + { + LIMITED_METHOD_CONTRACT; + + wLoadLevel = (unsigned short) loadLevel; + } +}; + + +class Module; +class AppDomain; + +class PlayerModuleInfo; + +// Module enumerator +class MulticoreJitModuleEnumerator +{ + virtual HRESULT OnModule(Module * pModule) = 0; + +public: + HRESULT EnumerateLoadedModules(AppDomain * pDomain); + HRESULT HandleAssembly(DomainAssembly * pAssembly); +}; + + +class PlayerModuleInfo; + +// MulticoreJitProfilePlayer manages background thread, playing back profile, storing result into code stoage, and gather statistics information + +class MulticoreJitProfilePlayer +{ +friend class MulticoreJitRecorder; + +private: + ADID m_DomainID; +#if defined(FEATURE_CORECLR) + ICLRPrivBinder * m_pBinderContext; +#endif + LONG m_nMySession; + unsigned m_nStartTime; + BYTE * m_pFileBuffer; + unsigned m_nFileSize; + MulticoreJitPlayerStat & m_stats; + MulticoreJitCounter & m_appdomainSession; + bool m_shouldAbort; + bool m_fAppxMode; + + Thread * m_pThread; + + unsigned m_nBlockingCount; + unsigned m_nMissingModule; + + int m_nLoadedModuleCount; + + unsigned m_busyWith; + + unsigned m_headerModuleCount; + unsigned m_moduleCount; + PlayerModuleInfo * m_pModules; + + void JITMethod(Module * pModule, unsigned methodIndex); + + HRESULT HandleModuleRecord(const ModuleRecord * pModule); + HRESULT HandleMethodRecord(unsigned * buffer, int count); + + bool CompileMethodDesc(Module * pModule, MethodDesc * pMD); + + HRESULT PlayProfile(); + + bool GroupWaitForModuleLoad(int pos); + + bool ShouldAbort(bool fast) const; + + HRESULT JITThreadProc(Thread * pThread); + + static DWORD WINAPI StaticJITThreadProc(void *args); + + void TraceSummary(); + + HRESULT UpdateModuleInfo(); + + bool HandleModuleDependency(unsigned jitInfo); + + HRESULT ReadCheckFile(const wchar_t * pFileName); + +#if defined(FEATURE_CORECLR) + DomainAssembly * LoadAssembly(SString & assemblyName); +#endif + +public: + + MulticoreJitProfilePlayer(AppDomain * pDomain, ICLRPrivBinder * pBinderContext, LONG nSession, bool fAppxMode); + + ~MulticoreJitProfilePlayer(); + + HRESULT ProcessProfile(const wchar_t * pFileName); + + HRESULT OnModule(Module * pModule); +}; + + +struct RecorderModuleInfo +{ + Module * pModule; + unsigned short methodCount; + unsigned short flags; + ModuleVersion moduleVersion; + SBuffer simpleName; + SBuffer assemblyName; + FileLoadLevel loadLevel; + + RecorderModuleInfo() + { + LIMITED_METHOD_CONTRACT; + + pModule = NULL; + methodCount = 0; + flags = 0; + loadLevel = FILE_LOAD_CREATE; + } + + bool SetModule(Module * pModule); +}; + + +class MulticoreJitRecorder +{ +private: + AppDomain * m_pDomain; // AutoStartProfile could be called from SystemDomain +#if defined(FEATURE_CORECLR) + ICLRPrivBinder * m_pBinderContext; +#endif + SString m_fullFileName; + MulticoreJitPlayerStat & m_stats; + + RecorderModuleInfo m_ModuleList[MAX_MODULES]; + unsigned m_ModuleCount; + unsigned m_ModuleDepCount; + + unsigned m_JitInfoArray[MAX_METHOD_ARRAY]; + LONG m_JitInfoCount; + + bool m_fFirstMethod; + bool m_fAborted; + bool m_fAppxMode; + +#ifndef FEATURE_PAL + static TP_TIMER * s_delayedWriteTimer; +#endif // !FEATURE_PAL + + + unsigned FindModule(Module * pModule); + unsigned GetModuleIndex(Module * pModule); + + HRESULT WriteModuleRecord(IStream * pStream, const RecorderModuleInfo & module); + + void RecordJitInfo(unsigned module, unsigned method); + + void AddAllModulesInAsm(DomainAssembly * pAssembly); + + HRESULT WriteOutput(IStream * pStream); + + HRESULT WriteOutput(); + + void PreRecordFirstMethod(); + +#ifndef FEATURE_PAL + static void CALLBACK WriteMulticoreJitProfiler(PTP_CALLBACK_INSTANCE pInstance, PVOID pvContext, PTP_TIMER pTimer); +#endif // !FEATURE_PAL + +public: + + MulticoreJitRecorder(AppDomain * pDomain, ICLRPrivBinder * pBinderContext, bool fAppxMode) + : m_stats(pDomain->GetMulticoreJitManager().GetStats()) + { + LIMITED_METHOD_CONTRACT; + + m_pDomain = pDomain; +#if defined(FEATURE_CORECLR) + m_pBinderContext = pBinderContext; +#endif + m_JitInfoCount = 0; + m_ModuleCount = 0; + m_ModuleDepCount = 0; + + m_fFirstMethod = true; + m_fAborted = false; + m_fAppxMode = fAppxMode; + +#if defined(FEATURE_APPX_BINDER) + + s_delayedWriteTimer = NULL; +#endif + + m_stats.Clear(); + } + +#ifndef FEATURE_PAL + static bool CloseTimer() + { + LIMITED_METHOD_CONTRACT; + + TP_TIMER * pTimer = InterlockedExchangeT(& s_delayedWriteTimer, NULL); + + if (pTimer == NULL) + { + return false; + } + + CloseThreadpoolTimer(pTimer); + + return true; + } + + ~MulticoreJitRecorder() + { + LIMITED_METHOD_CONTRACT; + + CloseTimer(); + } +#endif // !FEATURE_PAL + + bool IsAtFullCapacity() const + { + LIMITED_METHOD_CONTRACT; + + return (m_JitInfoCount >= (LONG) MAX_METHOD_ARRAY) || + (m_ModuleCount >= MAX_MODULES); + } + + void RecordMethodJit(MethodDesc * pMethod, bool application); + + PCODE RequestMethodCode(MethodDesc * pMethod, MulticoreJitManager * pManager); + + HRESULT StartProfile(const wchar_t * pRoot, const wchar_t * pFileName, int suffix, LONG nSession); + + HRESULT StopProfile(bool appDomainShutdown); + + void AbortProfile(); + + void RecordModuleLoad(Module * pModule, FileLoadLevel loadLevel); + + void AddModuleDependency(Module * pModule, FileLoadLevel loadLevel); +}; + +#ifdef MULTICOREJIT_LOGGING + +void _MulticoreJitTrace(const char * format, ...); + +#define MulticoreJitTrace(x) do { _MulticoreJitTrace x; } while (0) + +#else + +#define MulticoreJitTrace(x) + +#endif + +extern unsigned g_MulticoreJitDelay; // Delay in StartProfile +extern bool g_MulticoreJitEnabled; // Enable/Disable feature + + +inline bool PrivateEtwEnabled() +{ +#ifdef FEATURE_EVENT_TRACE + return ETW_PROVIDER_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER) != 0; +#else // FEATURE_EVENT_TRACE + return FALSE; +#endif // FEATURE_EVENT_TRACE +} + +void MulticoreJitFireEtw(const wchar_t * pAction, const wchar_t * pTarget, int p1, int p2, int p3); + +void MulticoreJitFireEtwA(const wchar_t * pAction, const char * pTarget, int p1, int p2, int p3); + +void MulticoreJitFireEtwMethodCodeReturned(MethodDesc * pMethod); + +#define _FireEtwMulticoreJit(String1, String2, Int1, Int2, Int3) if (PrivateEtwEnabled()) MulticoreJitFireEtw (String1, String2, Int1, Int2, Int3) +#define _FireEtwMulticoreJitA(String1, String2, Int1, Int2, Int3) if (PrivateEtwEnabled()) MulticoreJitFireEtwA(String1, String2, Int1, Int2, Int3) +#define _FireEtwMulticoreJitMethodCodeReturned(pMethod) if(PrivateEtwEnabled()) MulticoreJitFireEtwMethodCodeReturned(pMethod) + |