Cache the random state on the InlineStrategy instead of on the compiler
instance so that the state is reinitialized and private to each jit request.
That way the random policy evaluations made compiling one method won't
alter the evaluations for subsequent methods. This should make it somewhat
easier to do A/B comparisons under jit stress when changing the jit.
Make it possible to enable the RandomPolicy outside of stress. This may
prove useful in various randomized inline performance studies or as
a simple stress mode on its own.
Random state seed is built from an external seed value (via JitStress or
JitInlinePolicyRandom) and an internal seed value (method hash), so that
random sequences potentially differ for each method but are deterministic
across runs and changes to the jit.
Commit migrated from https://github.com/dotnet/coreclr/commit/
7697dec7db3e34239ffa33d8867de12f7176e415
SIMDVectorHandle = nullptr;
#endif
-#ifdef DEBUG
- inlRNG = nullptr;
-#endif
-
compUsesThrowHelper = false;
}
#endif
}
-#ifdef DEBUG
- CLRRandom* inlRNG;
-#endif
-
//--------------------- Info about the procedure --------------------------
struct Info
, m_HasForceViaDiscretionary(false)
#if defined(DEBUG) || defined(INLINE_DATA)
, m_MethodXmlFilePosition(0)
+ , m_Random(nullptr)
#endif // defined(DEBUG) || defined(INLINE_DATA)
{
ReplayPolicy::FinalizeXml();
}
+//------------------------------------------------------------------------
+// GetRandom: setup or access random state
+//
+// Return Value:
+// New or pre-existing random state.
+//
+// Notes:
+// Random state is kept per jit compilation request. Seed is partially
+// specified externally (via stress or policy setting) and partially
+// specified internally via method hash.
+
+CLRRandom* InlineStrategy::GetRandom()
+{
+ if (m_Random == nullptr)
+ {
+ int externalSeed = 0;
+ if (m_Compiler->compRandomInlineStress())
+ {
+ externalSeed = getJitStressLevel();
+ }
+
+ int randomPolicyFlag = JitConfig.JitInlinePolicyRandom();
+ if (randomPolicyFlag != 0)
+ {
+ externalSeed = randomPolicyFlag;
+ }
+
+ int internalSeed = m_Compiler->info.compMethodHash();
+
+ assert(externalSeed != 0);
+ assert(internalSeed != 0);
+
+ int seed = externalSeed ^ internalSeed;
+
+ m_Random = new (m_Compiler, CMK_Inlining) CLRRandom();
+ m_Random->Init(seed);
+ }
+
+ return m_Random;
+}
+
#endif // defined(DEBUG) || defined(INLINE_DATA)
//------------------------------------------------------------------------
m_MethodXmlFilePosition = val;
}
+ // Set up or access random state (for use by RandomPolicy)
+ CLRRandom* GetRandom();
+
#endif // defined(DEBUG) || defined(INLINE_DATA)
// Some inline limit values
bool m_HasForceViaDiscretionary;
#if defined(DEBUG) || defined(INLINE_DATA)
- long m_MethodXmlFilePosition;
+ long m_MethodXmlFilePosition;
+ CLRRandom* m_Random;
#endif // defined(DEBUG) || defined(INLINE_DATA)
};
#ifdef DEBUG
// Optionally install the RandomPolicy.
- bool useRandomPolicy = compiler->compRandomInlineStress();
+ const bool useRandomPolicyForStress = compiler->compRandomInlineStress();
+ const bool useRandomPolicy = (JitConfig.JitInlinePolicyRandom() != 0);
- if (useRandomPolicy)
+ if (useRandomPolicyForStress || useRandomPolicy)
{
- unsigned seed = getJitStressLevel();
- assert(seed != 0);
- return new (compiler, CMK_Inlining) RandomPolicy(compiler, isPrejitRoot, seed);
+ return new (compiler, CMK_Inlining) RandomPolicy(compiler, isPrejitRoot);
}
#endif // DEBUG
return propagate;
}
-#ifdef DEBUG
+#if defined(DEBUG) || defined(INLINE_DATA)
//------------------------------------------------------------------------
// RandomPolicy: construct a new RandomPolicy
// Arguments:
// compiler -- compiler instance doing the inlining (root compiler)
// isPrejitRoot -- true if this compiler is prejitting the root method
-// seed -- seed value for the random number generator
-RandomPolicy::RandomPolicy(Compiler* compiler, bool isPrejitRoot, unsigned seed)
+RandomPolicy::RandomPolicy(Compiler* compiler, bool isPrejitRoot)
: LegalPolicy(isPrejitRoot)
, m_RootCompiler(compiler)
, m_Random(nullptr)
, m_IsForceInline(false)
, m_IsForceInlineKnown(false)
{
- // If necessary, setup and seed the random state.
- if (compiler->inlRNG == nullptr)
- {
- compiler->inlRNG = new (compiler, CMK_Inlining) CLRRandom();
-
- unsigned hash = m_RootCompiler->info.compMethodHash();
- assert(hash != 0);
- assert(seed != 0);
- int hashSeed = static_cast<int>(hash ^ seed);
- compiler->inlRNG->Init(hashSeed);
- }
-
- m_Random = compiler->inlRNG;
+ m_Random = compiler->m_inlineStrategy->GetRandom();
}
//------------------------------------------------------------------------
}
}
-#endif // DEBUG
+#endif // defined(DEBUG) || defined(INLINE_DATA)
#ifdef _MSC_VER
// Disable warning about new array member initialization behavior
bool m_IsNoReturnKnown : 1;
};
-#ifdef DEBUG
+#if defined(DEBUG) || defined(INLINE_DATA)
// RandomPolicy implements a policy that inlines at random.
// It is mostly useful for stress testing.
{
public:
// Construct a RandomPolicy
- RandomPolicy(Compiler* compiler, bool isPrejitRoot, unsigned seed);
+ RandomPolicy(Compiler* compiler, bool isPrejitRoot);
// Policy observations
void NoteSuccess() override;
bool m_IsForceInlineKnown : 1;
};
-#endif // DEBUG
+#endif // defined(DEBUG) || defined(INLINE_DATA)
// DiscretionaryPolicy is a variant of the enhanced legacy policy. It
// differs in that there is no ALWAYS_INLINE class, there is no IL
CONFIG_INTEGER(JitInlinePolicyDiscretionary, W("JitInlinePolicyDiscretionary"), 0)
CONFIG_INTEGER(JitInlinePolicyFull, W("JitInlinePolicyFull"), 0)
CONFIG_INTEGER(JitInlinePolicySize, W("JitInlinePolicySize"), 0)
+CONFIG_INTEGER(JitInlinePolicyRandom, W("JitInlinePolicyRandom"), 0) // nozero enables; value is the external random
+ // seed
CONFIG_INTEGER(JitInlinePolicyReplay, W("JitInlinePolicyReplay"), 0)
CONFIG_STRING(JitNoInlineRange, W("JitNoInlineRange"))
CONFIG_STRING(JitInlineReplayFile, W("JitInlineReplayFile"))