Bug 1182516 - Add Chaos Mode environment variable MOZ_CHAOSMODE. r=roc

This commit is contained in:
Benoit Girard 2015-07-14 17:29:23 -04:00
parent ce65d9290b
commit 2e648924e7
9 changed files with 42 additions and 29 deletions

View File

@ -7,9 +7,11 @@
#include "mozilla/ChaosMode.h" #include "mozilla/ChaosMode.h"
namespace mozilla { namespace mozilla {
namespace detail { namespace detail {
Atomic<uint32_t> gChaosModeCounter(0); Atomic<uint32_t> gChaosModeCounter(0);
ChaosFeature gChaosFeatures = None;
} /* namespace detail */ } /* namespace detail */
} /* namespace mozilla */ } /* namespace mozilla */

View File

@ -15,8 +15,24 @@
namespace mozilla { namespace mozilla {
enum ChaosFeature {
None = 0x0,
// Altering thread scheduling.
ThreadScheduling = 0x1,
// Altering network request scheduling.
NetworkScheduling = 0x2,
// Altering timer scheduling.
TimerScheduling = 0x4,
// Read and write less-than-requested amounts.
IOAmounts = 0x8,
// Iterate over hash tables in random order.
HashTableIteration = 0x10,
Any = 0xffffffff,
};
namespace detail { namespace detail {
extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter; extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter;
extern MFBT_DATA ChaosFeature gChaosFeatures;
} // namespace detail } // namespace detail
/** /**
@ -27,32 +43,17 @@ extern MFBT_DATA Atomic<uint32_t> gChaosModeCounter;
class ChaosMode class ChaosMode
{ {
public: public:
enum ChaosFeature { static void SetChaosFeature(ChaosFeature aChaosFeature)
None = 0x0, {
// Altering thread scheduling. detail::gChaosFeatures = aChaosFeature;
ThreadScheduling = 0x1, }
// Altering network request scheduling.
NetworkScheduling = 0x2,
// Altering timer scheduling.
TimerScheduling = 0x4,
// Read and write less-than-requested amounts.
IOAmounts = 0x8,
// Iterate over hash tables in random order.
HashTableIteration = 0x10,
Any = 0xffffffff,
};
private:
// Change this to any non-None value to activate ChaosMode.
static const ChaosFeature sChaosFeatures = None;
public:
static bool isActive(ChaosFeature aFeature) static bool isActive(ChaosFeature aFeature)
{ {
if (detail::gChaosModeCounter > 0) { if (detail::gChaosModeCounter > 0) {
return true; return true;
} }
return sChaosFeatures & aFeature; return detail::gChaosFeatures & aFeature;
} }
/** /**

View File

@ -275,7 +275,7 @@ nsSocketTransportService::AddToPollList(SocketContext *sock)
} }
uint32_t newSocketIndex = mActiveCount; uint32_t newSocketIndex = mActiveCount;
if (ChaosMode::isActive(ChaosMode::NetworkScheduling)) { if (ChaosMode::isActive(ChaosFeature::NetworkScheduling)) {
newSocketIndex = ChaosMode::randomUint32LessThan(mActiveCount + 1); newSocketIndex = ChaosMode::randomUint32LessThan(mActiveCount + 1);
PodMove(mActiveList + newSocketIndex + 1, mActiveList + newSocketIndex, PodMove(mActiveList + newSocketIndex + 1, mActiveList + newSocketIndex,
mActiveCount - newSocketIndex); mActiveCount - newSocketIndex);

View File

@ -1626,7 +1626,7 @@ nsHttpConnection::OnWriteSegment(char *buf,
return NS_ERROR_FAILURE; // stop iterating return NS_ERROR_FAILURE; // stop iterating
} }
if (ChaosMode::isActive(ChaosMode::IOAmounts) && if (ChaosMode::isActive(ChaosFeature::IOAmounts) &&
ChaosMode::randomUint32LessThan(2)) { ChaosMode::randomUint32LessThan(2)) {
// read 1...count bytes // read 1...count bytes
count = ChaosMode::randomUint32LessThan(count) + 1; count = ChaosMode::randomUint32LessThan(count) + 1;

View File

@ -56,7 +56,7 @@ InsertTransactionSorted(nsTArray<nsHttpTransaction*> &pendingQ, nsHttpTransactio
for (int32_t i=pendingQ.Length()-1; i>=0; --i) { for (int32_t i=pendingQ.Length()-1; i>=0; --i) {
nsHttpTransaction *t = pendingQ[i]; nsHttpTransaction *t = pendingQ[i];
if (trans->Priority() >= t->Priority()) { if (trans->Priority() >= t->Priority()) {
if (ChaosMode::isActive(ChaosMode::NetworkScheduling)) { if (ChaosMode::isActive(ChaosFeature::NetworkScheduling)) {
int32_t samePriorityCount; int32_t samePriorityCount;
for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) { for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) {
if (pendingQ[i - samePriorityCount]->Priority() != trans->Priority()) { if (pendingQ[i - samePriorityCount]->Priority() != trans->Priority()) {

View File

@ -3123,7 +3123,17 @@ XREMain::XRE_mainInit(bool* aExitFlag)
StartupTimeline::Record(StartupTimeline::MAIN); StartupTimeline::Record(StartupTimeline::MAIN);
if (ChaosMode::isActive(ChaosMode::Any)) { if (PR_GetEnv("MOZ_CHAOSMODE")) {
ChaosFeature feature = ChaosFeature::Any;
long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
if (featureInt) {
// NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
feature = static_cast<ChaosFeature>(featureInt);
}
ChaosMode::SetChaosFeature(feature);
}
if (ChaosMode::isActive(ChaosFeature::Any)) {
printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n"); printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
} }

View File

@ -236,7 +236,7 @@ TimerThread::Run()
if (mSleeping) { if (mSleeping) {
// Sleep for 0.1 seconds while not firing timers. // Sleep for 0.1 seconds while not firing timers.
uint32_t milliseconds = 100; uint32_t milliseconds = 100;
if (ChaosMode::isActive(ChaosMode::TimerScheduling)) { if (ChaosMode::isActive(ChaosFeature::TimerScheduling)) {
milliseconds = ChaosMode::randomUint32LessThan(200); milliseconds = ChaosMode::randomUint32LessThan(200);
} }
waitFor = PR_MillisecondsToInterval(milliseconds); waitFor = PR_MillisecondsToInterval(milliseconds);
@ -320,7 +320,7 @@ TimerThread::Run()
// interval is so small we should not wait at all). // interval is so small we should not wait at all).
double microseconds = (timeout - now).ToMilliseconds() * 1000; double microseconds = (timeout - now).ToMilliseconds() * 1000;
if (ChaosMode::isActive(ChaosMode::TimerScheduling)) { if (ChaosMode::isActive(ChaosFeature::TimerScheduling)) {
// The mean value of sFractions must be 1 to ensure that // The mean value of sFractions must be 1 to ensure that
// the average of a long sequence of timeouts converges to the // the average of a long sequence of timeouts converges to the
// actual sum of their times. // actual sum of their times.

View File

@ -95,7 +95,7 @@ nsEventQueue::PutEvent(already_AddRefed<nsIRunnable>&& aRunnable)
// Avoid calling AddRef+Release while holding our monitor. // Avoid calling AddRef+Release while holding our monitor.
nsCOMPtr<nsIRunnable> event(aRunnable); nsCOMPtr<nsIRunnable> event(aRunnable);
if (ChaosMode::isActive(ChaosMode::ThreadScheduling)) { if (ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
// With probability 0.5, yield so other threads have a chance to // With probability 0.5, yield so other threads have a chance to
// dispatch events to this queue first. // dispatch events to this queue first.
if (ChaosMode::randomUint32LessThan(2)) { if (ChaosMode::randomUint32LessThan(2)) {

View File

@ -284,7 +284,7 @@ private:
static void static void
SetupCurrentThreadForChaosMode() SetupCurrentThreadForChaosMode()
{ {
if (!ChaosMode::isActive(ChaosMode::ThreadScheduling)) { if (!ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
return; return;
} }
@ -926,7 +926,7 @@ nsThread::SetPriority(int32_t aPriority)
pri = PR_PRIORITY_NORMAL; pri = PR_PRIORITY_NORMAL;
} }
// If chaos mode is active, retain the randomly chosen priority // If chaos mode is active, retain the randomly chosen priority
if (!ChaosMode::isActive(ChaosMode::ThreadScheduling)) { if (!ChaosMode::isActive(ChaosFeature::ThreadScheduling)) {
PR_SetThreadPriority(mThread, pri); PR_SetThreadPriority(mThread, pri);
} }