summaryrefslogtreecommitdiff
path: root/src/vm/multicorejitimpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/multicorejitimpl.h')
-rw-r--r--src/vm/multicorejitimpl.h497
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)
+