#define INCLUDE_ALLOW_VMCORE
#include "includeCheck.h"
+#include <stdarg.h>
+
#include "vm_atomic.h"
#include "vm_basic_types.h"
#include "vm_basic_defs.h"
MX_Rank rank,
Bool isBelowBull);
-#if defined(VMX86_STATS)
-#define MXUSER_STATS // stats "only inside the VMX" when requested
-#endif
#endif
#if defined(VMX86_DEBUG)
#endif
#if defined(MXUSER_DEBUG)
-Bool MXUser_IsCurThreadHoldingLocks(void);
void MXUser_TryAcquireFailureControl(Bool (*func)(const char *lockName));
+Bool MXUser_IsCurThreadHoldingLocks(void);
#endif
-#if defined(MXUSER_STATS)
void MXUser_StatisticsControl(double contentionRatio,
uint64 minCount);
void MXUser_PerLockData(void);
-#endif
+void MXUser_SetStatsFunc(void *context,
+ uint32 maxLineLength,
+ void (*statsFunc)(void *context,
+ const char *fmt,
+ va_list ap));
void MXUser_SetInPanic(void);
Bool MXUser_InPanic(void);
barrier->configCount = count;
barrier->curContext = 0;
- barrier->header.name = properName;
barrier->header.signature = MXUSER_BARRIER_SIGNATURE;
+ barrier->header.name = properName;
barrier->header.rank = rank;
+ barrier->header.serialNumber = MXUserAllocSerialNumber();
barrier->header.dumpFunc = MXUserDumpBarrier;
-
-#if defined(MXUSER_STATS)
barrier->header.statsFunc = NULL;
- barrier->header.identifier = MXUserAllocID();
-#endif
+
+ MXUserAddToList(&barrier->header);
return barrier;
}
__FUNCTION__);
}
+ MXUserRemoveFromList(&barrier->header);
+
MXUser_DestroyCondVar(barrier->contexts[0].condVar);
MXUser_DestroyCondVar(barrier->contexts[1].condVar);
MXUser_DestroyExclLock(barrier->lock);
};
-#if defined(MXUSER_STATS)
/*
*-----------------------------------------------------------------------------
*
}
}
}
-#endif
/*
MX_Rank rank) // IN:
{
char *properName;
- MXUserStats *stats;
MXUserExclLock *lock;
lock = Util_SafeCalloc(1, sizeof(*lock));
return NULL;
}
- lock->header.name = properName;
lock->header.signature = MXUSER_EXCL_SIGNATURE;
+ lock->header.name = properName;
lock->header.rank = rank;
+ lock->header.serialNumber = MXUserAllocSerialNumber();
lock->header.dumpFunc = MXUserDumpExclLock;
-#if defined(MXUSER_STATS)
- lock->header.statsFunc = MXUserStatsActionExcl;
- lock->header.identifier = MXUserAllocID();
+ if (MXUserStatsEnabled()) {
+ MXUserStats *stats = Util_SafeCalloc(1, sizeof(*stats));
- stats = Util_SafeCalloc(1, sizeof(*stats));
+ MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
+ MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
- MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
- MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
-#else
- stats = NULL;
-#endif
-
- Atomic_WritePtr(&lock->statsMem, stats);
+ lock->header.statsFunc = MXUserStatsActionExcl;
+ Atomic_WritePtr(&lock->statsMem, stats);
+ } else {
+ lock->header.statsFunc = NULL;
+ Atomic_WritePtr(&lock->statsMem, NULL);
+ }
MXUserAddToList(&lock->header);
typedef struct MXUserHeader {
uint32 signature;
- MX_Rank rank;
char *name;
- uint32 identifier;
+ MX_Rank rank;
+ uint32 serialNumber;
void (*dumpFunc)(struct MXUserHeader *);
-
-#if defined(MXUSER_STATS)
void (*statsFunc)(struct MXUserHeader *);
ListItem item;
-#endif
} MXUserHeader;
MXUserBasicStats basicStats; // total held statistics
} MXUserReleaseStats;
-uint32 MXUserAllocID(void);
+uint32 MXUserAllocSerialNumber(void);
-#if defined(MXUSER_STATS)
void MXUserAddToList(MXUserHeader *header);
void MXUserRemoveFromList(MXUserHeader *header);
-#else
-static INLINE void
-MXUserAddToList(MXUserHeader *header)
-{
- return;
-}
-static INLINE void
-MXUserRemoveFromList(MXUserHeader *header)
-{
- return;
-}
-#endif
+Bool MXUserStatsEnabled(void);
typedef struct MXUserHisto MXUserHisto;
};
-#if defined(MXUSER_STATS)
/*
*-----------------------------------------------------------------------------
*
}
}
}
-#endif
/*
properName = Util_SafeStrdup(userName);
}
+ lock->header.signature = MXUSER_RW_SIGNATURE;
+ lock->header.name = properName;
+ lock->header.rank = rank;
+ lock->header.serialNumber = MXUserAllocSerialNumber();
+ lock->header.dumpFunc = MXUserDumpRWLock;
+
/*
* Always attempt to use native locks when they are available. If, for some
* reason, a native lock should be available but isn't, fall back to using
lock->useNative = useNative && MXUserNativeRWInit(&lock->nativeLock);
- if (lock->useNative) {
-#if defined(MXUSER_STATS)
- /* stats builds need an internal recursive lock for data integrity */
-
- lockInited = MXRecLockInit(&lock->recursiveLock);
-
- if (!lockInited) {
- MXUserNativeRWDestroy(&lock->nativeLock);
- }
-#else
- lockInited = TRUE;
-#endif
- } else {
- lockInited = MXRecLockInit(&lock->recursiveLock);
- }
+ lockInited = MXRecLockInit(&lock->recursiveLock);
if (LIKELY(lockInited)) {
- MXUserStats *stats;
-
lock->holderTable = HashTable_Alloc(256,
HASH_INT_KEY | HASH_FLAG_ATOMIC,
MXUserFreeHashEntry);
- lock->header.name = properName;
- lock->header.signature = MXUSER_RW_SIGNATURE;
- lock->header.rank = rank;
- lock->header.dumpFunc = MXUserDumpRWLock;
+ if (MXUserStatsEnabled()) {
+ MXUserStats *stats = Util_SafeCalloc(1, sizeof(*stats));
-#if defined(MXUSER_STATS)
- lock->header.statsFunc = MXUserStatsActionRW;
- lock->header.identifier = MXUserAllocID();
+ MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
+ MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
- stats = Util_SafeCalloc(1, sizeof(*stats));
-
- MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
- MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
-#else
- stats = NULL;
-#endif
+ lock->header.statsFunc = MXUserStatsActionRW;
+ Atomic_WritePtr(&lock->statsMem, stats);
+ } else {
+ lock->header.statsFunc = NULL;
+ Atomic_WritePtr(&lock->statsMem, NULL);
+ }
MXUserAddToList(&lock->header);
} else {
+ if (lock->useNative) {
+ MXUserNativeRWDestroy(&lock->nativeLock);
+ }
+
free(properName);
free(lock);
lock = NULL;
MXUserDumpAndPanic(&lock->header, "%s: Internal error (%d)\n",
__FUNCTION__, err);
}
-
-#if defined(MXUSER_STATS)
- MXRecLockDestroy(&lock->recursiveLock);
-#endif
- } else {
- MXRecLockDestroy(&lock->recursiveLock);
}
+ MXRecLockDestroy(&lock->recursiveLock);
+
MXUserRemoveFromList(&lock->header);
stats = (MXUserStats *) Atomic_ReadPtr(&lock->statsMem);
struct MX_MutexRec *vmmLock;
};
-#if defined(MXUSER_STATS)
+
/*
*-----------------------------------------------------------------------------
*
}
}
}
-#endif
/*
Bool beSilent) // IN:
{
char *properName;
- MXUserStats *stats;
MXUserRecLock *lock;
lock = Util_SafeCalloc(1, sizeof(*lock));
lock->vmmLock = NULL;
- lock->header.name = properName;
lock->header.signature = MXUSER_REC_SIGNATURE;
+ lock->header.name = properName;
lock->header.rank = rank;
+ lock->header.serialNumber = MXUserAllocSerialNumber();
lock->header.dumpFunc = MXUserDumpRecLock;
-#if defined(MXUSER_STATS)
- lock->header.statsFunc = MXUserStatsActionRec;
- lock->header.identifier = MXUserAllocID();
-#endif
-
- if (beSilent) {
- stats = NULL;
+ if (beSilent || !MXUserStatsEnabled()) {
+ lock->header.statsFunc = NULL;
+ Atomic_WritePtr(&lock->statsMem, NULL);
} else {
-#if defined(MXUSER_STATS)
- stats = Util_SafeCalloc(1, sizeof(*stats));
+ MXUserStats *stats = Util_SafeCalloc(1, sizeof(*stats));
MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
MXUserBasicStatsSetUp(&stats->heldStats, MXUSER_STAT_CLASS_HELD);
-#else
- stats = NULL;
-#endif
- }
- Atomic_WritePtr(&lock->statsMem, stats);
+ lock->header.statsFunc = MXUserStatsActionRec;
+ Atomic_WritePtr(&lock->statsMem, stats);
+ }
MXUserAddToList(&lock->header);
lock = Util_SafeCalloc(1, sizeof(*lock));
- lock->header.name = Str_SafeAsprintf(NULL, "MX_%p", mutex);
-
lock->header.signature = MXUSER_REC_SIGNATURE;
+ lock->header.name = Str_SafeAsprintf(NULL, "MX_%p", mutex);
lock->header.rank = rank;
+ lock->header.serialNumber = MXUserAllocSerialNumber();
lock->header.dumpFunc = NULL;
-
-#if defined(MXUSER_STATS)
lock->header.statsFunc = NULL;
- lock->header.identifier = MXUserAllocID();
-#endif
Atomic_WritePtr(&lock->statsMem, NULL);
#endif // _WIN32
-#if defined(MXUSER_STATS)
/*
*-----------------------------------------------------------------------------
*
}
}
}
-#endif
/*
if (LIKELY(MXUserInit(&sema->nativeSemaphore) == 0)) {
MXUserStats *stats;
- sema->header.name = properName;
sema->header.signature = MXUSER_SEMA_SIGNATURE;
+ sema->header.name = properName;
sema->header.rank = rank;
+ sema->header.serialNumber = MXUserAllocSerialNumber();
sema->header.dumpFunc = MXUserDumpSemaphore;
-#if defined(MXUSER_STATS)
- sema->header.statsFunc = MXUserStatsActionSema;
- sema->header.identifier = MXUserAllocID();
+ if (MXUserStatsEnabled()) {
+ sema->header.statsFunc = MXUserStatsActionSema;
- stats = Util_SafeCalloc(1, sizeof(*stats));
+ stats = Util_SafeCalloc(1, sizeof(*stats));
- MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
-#else
- stats = NULL;
-#endif
+ MXUserAcquisitionStatsSetUp(&stats->acquisitionStats);
- Atomic_WritePtr(&sema->statsMem, stats);
+ Atomic_WritePtr(&sema->statsMem, stats);
+ } else {
+ sema->header.statsFunc = NULL;
+ Atomic_WritePtr(&sema->statsMem, NULL);
+ }
MXUserAddToList(&sema->header);
} else {
#include "hostinfo.h"
#include "log.h"
#include "logFixed.h"
-#if defined(MXUSER_STATS)
#include "statsLog.h"
-#endif
#define BINS_PER_DECADE 100
static double mxUserContentionRatio = 0.0; // always "off"
static uint64 mxUserContentionCount = 0; // always "off"
-#if defined(MXUSER_STATS)
static Atomic_Ptr mxLockMemPtr; // internal singleton lock
static ListItem *mxUserLockList; // list of all MXUser locks
-#endif
typedef struct {
void *address;
TopOwner ownerArray[TOPOWNERS]; // List of top owners
};
+static char *mxUserHistoLine = NULL;
+static uint32 mxUserMaxLineLength = 0;
+static void *mxUserStatsContext = NULL;
+static void (*mxUserStatsFunc)(void *context,
+ const char *fmt,
+ va_list ap) = NULL;
+
-#if defined(MXUSER_STATS)
/*
*-----------------------------------------------------------------------------
*
MXRecLockRelease(listLock);
}
}
-#endif
/*
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUserStatsLog --
+ *
+ * Output the statistics data
+ *
+ * Results:
+ * As above
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+MXUserStatsLog(const char *fmt, // IN:
+ ...) // IN:
+{
+ va_list ap;
+
+ ASSERT(mxUserStatsFunc);
+
+ va_start(ap, fmt);
+ (*mxUserStatsFunc)(mxUserStatsContext, fmt, ap);
+ va_end(ap);
+}
+
+
/*
*-----------------------------------------------------------------------------
*
ASSERT(header);
ASSERT(histo);
-#if defined(MXUSER_STATS)
if (histo->totalSamples) {
char *p;
uint32 i;
uint32 spaceLeft;
- static uint32 maxLine = 0;
- static char *histoLine = NULL;
-
- /*
- * Statistics are reported from a single thread. This avoids allocating
- * a potentially large buffer on the stack.
- */
-
- if (maxLine == 0) {
- maxLine = Log_MaxLineLength(); // includes terminating NUL
- ASSERT(maxLine >= 1024); // assert a rational minimum
+ ASSERT(mxUserHistoLine);
- histoLine = Util_SafeMalloc(maxLine);
- }
-
- i = Str_Sprintf(histoLine, maxLine,
+ i = Str_Sprintf(mxUserHistoLine, mxUserMaxLineLength,
"MXUser: h l=%u t=%s min=%"FMT64"u max=%"FMT64"u\n",
- header->identifier, histo->typeName, histo->minValue,
+ header->serialNumber, histo->typeName, histo->minValue,
histo->maxValue);
/*
* properly terminated no matter what happens.
*/
- p = &histoLine[i - 1];
- spaceLeft = maxLine - i - 2;
+ p = &mxUserHistoLine[i - 1];
+ spaceLeft = mxUserMaxLineLength - i - 2;
/* Add as many histogram bins as possible within the line limitations */
for (i = 0; i < histo->numBins; i++) {
}
}
- StatsLog(histoLine);
+ MXUserStatsLog("%s", mxUserHistoLine);
- i = Str_Sprintf(histoLine, maxLine, "MXUser: ht l=%u t=%s\n",
- header->identifier, histo->typeName);
+ i = Str_Sprintf(mxUserHistoLine, mxUserMaxLineLength,
+ "MXUser: ht l=%u t=%s\n", header->serialNumber,
+ histo->typeName);
- p = &histoLine[i - 1];
- spaceLeft = maxLine - i - 2;
+ p = &mxUserHistoLine[i - 1];
+ spaceLeft = mxUserMaxLineLength - i - 2;
for (i = 0; i < TOPOWNERS; i++) {
if (histo->ownerArray[i].address != NULL) {
}
}
- StatsLog("%s", histoLine);
+ MXUserStatsLog("%s", mxUserHistoLine);
}
-#endif
}
*-----------------------------------------------------------------------------
*/
+static double
+MXUserSqrt(double x) // IN: hack until next round when FP goes away
+{
+ double xn;
+ double xn1 = x;
+
+ do {
+ xn = xn1;
+ xn1 = (xn + x/xn) / 2.0;
+ } while (fabs(xn1 - xn) > 1E-10);
+
+ return xn1;
+}
+
void
MXUserDumpBasicStats(MXUserBasicStats *stats, // IN:
MXUserHeader *header) // IN:
{
-#if defined(MXUSER_STATS)
uint64 stdDev;
if (stats->numSamples < 2) {
mean = ((double) stats->timeSum) / num;
variance = (stats->timeSquaredSum - (num*mean*mean)) / (num - 1.0);
- stdDev = (variance < 0.0) ? 0 : (uint64) (sqrt(variance) + 0.5);
+ stdDev = (variance < 0.0) ? 0 : (uint64) (MXUserSqrt(variance) + 0.5);
}
- StatsLog("MXUser: e l=%u t=%s c=%"FMT64"u min=%"FMT64"u "
- "max=%"FMT64"u mean=%"FMT64"u sd=%"FMT64"u\n",
- header->identifier, stats->typeName,
- stats->numSamples, stats->minTime, stats->maxTime,
- stats->timeSum/stats->numSamples, stdDev);
-#endif
+ MXUserStatsLog("MXUser: e l=%u t=%s c=%"FMT64"u min=%"FMT64"u "
+ "max=%"FMT64"u mean=%"FMT64"u sd=%"FMT64"u\n",
+ header->serialNumber, stats->typeName,
+ stats->numSamples, stats->minTime, stats->maxTime,
+ stats->timeSum/stats->numSamples, stdDev);
}
MXUserDumpAcquisitionStats(MXUserAcquisitionStats *stats, // IN:
MXUserHeader *header) // IN:
{
-#if defined(MXUSER_STATS)
if (stats->numAttempts > 0) {
if (stats->numSuccesses > 0) {
MXUserDumpBasicStats(&stats->basicStats, header);
}
- StatsLog("MXUser: ce l=%u a=%"FMT64"u s=%"FMT64"u sc=%"FMT64"u "
- "sct=%"FMT64"u t=%"FMT64"u\n",
- header->identifier,
- stats->numAttempts,
- stats->numSuccesses,
- stats->numSuccessesContended,
- stats->successContentionTime,
- stats->totalContentionTime);
+ MXUserStatsLog("MXUser: ce l=%u a=%"FMT64"u s=%"FMT64"u sc=%"FMT64"u "
+ "sct=%"FMT64"u t=%"FMT64"u\n",
+ header->serialNumber,
+ stats->numAttempts,
+ stats->numSuccesses,
+ stats->numSuccessesContended,
+ stats->successContentionTime,
+ stats->totalContentionTime);
}
-#endif
}
}
-#if defined(MXUSER_STATS)
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUserStatsEnabled --
+ *
+ * Are statistics keeping enabled
+ *
+ * Results:
+ * TRUE Yes
+ * FALSE NO
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+MXUserStatsEnabled(void)
+{
+ return (mxUserStatsFunc != NULL) && (mxUserMaxLineLength > 0);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUser_SetStatsFunc --
+ *
+ * Establish statistics taking and reporting. This is done by registering
+ * a statistics context, a reporting function and a maximum line length.
+ *
+ * A maxLineLength of zero (0) and/or a statsFunc of NULL will
+ * disable/prevent statistics gathering.
+ *
+ * Results:
+ * As above
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+MXUser_SetStatsFunc(void *context, // IN:
+ uint32 maxLineLength, // IN:
+ void (*statsFunc)(void *context, // IN:
+ const char *fmt,
+ va_list ap))
+{
+ ASSERT(maxLineLength >= 1024); // assert a rational minimum
+
+ free(mxUserHistoLine);
+ mxUserHistoLine = Util_SafeMalloc(maxLineLength);
+
+ mxUserStatsContext = context;
+ mxUserMaxLineLength = maxLineLength;
+ mxUserStatsFunc = statsFunc;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
if (listLock && MXRecLockTryAcquire(listLock)) {
ListItem *entry;
- uint32 highestID;
- static uint32 lastReportedID = 0;
+ uint32 highestSerialNumber;
+ static uint32 lastReportedSerialNumber = 0;
- highestID = lastReportedID;
+ highestSerialNumber = lastReportedSerialNumber;
LIST_SCAN(entry, mxUserLockList) {
MXUserHeader *header = LIST_CONTAINER(entry, MXUserHeader, item);
/* Log the ID information for a lock that did exist previously */
- if (header->identifier > lastReportedID) {
- StatsLog("MXUser: n n=%s l=%d r=0x%x\n", header->name,
- header->identifier, header->rank);
+ if (header->serialNumber > lastReportedSerialNumber) {
+ MXUserStatsLog("MXUser: n n=%s l=%d r=0x%x\n", header->name,
+ header->serialNumber, header->rank);
- if (header->identifier > highestID) {
- highestID = header->identifier;
+ if (header->serialNumber > highestSerialNumber) {
+ highestSerialNumber = header->serialNumber;
}
}
}
}
- lastReportedID = highestID;
+ lastReportedSerialNumber = highestSerialNumber;
MXRecLockRelease(listLock);
}
}
-#endif
/*
*-----------------------------------------------------------------------------
*
- * MXUserAllocID --
+ * MXUserAllocSerialNumber --
*
- * Allocate and return an MXUser identifier
+ * Allocate and return an MXUser serial number.
*
- * MXUser identifiers are never recycled.
+ * MXUser serial numbers are never recycled.
*
* Results:
* As above.
*/
uint32
-MXUserAllocID(void)
+MXUserAllocSerialNumber(void)
{
- static Atomic_uint32 firstFreeID = { 1 }; // must start not zero
+ static Atomic_uint32 firstFreeSerialNumber = { 1 }; // must start not zero
- return Atomic_FetchAndInc(&firstFreeID);
+ return Atomic_FetchAndInc(&firstFreeSerialNumber);
}