singrdk/base/Kernel/Native/Monitoring.cpp

884 lines
28 KiB
C++
Raw Normal View History

2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Monitoring.cpp
//
// Note:
//
// This stuff in here provides a ring-buffer like way to organize monitoring
// buffer entries. Interrupts are *never* disabled, all synchronization is
// done in a non-blocking fashion.
//
// You should *never* get incorrect values from the basic events, the worst
// thing that should happen is that a value is not available anymore, due to
// buffer wrap around. Entries should never be corrupted.
//
// This buffer should be thread and MP safe. Therefore only one buffer is
// currently used for the whole system.
//
// All events may have an additional pointer to a variably sized string in a
// second buffer. Guarantees for data in this buffer are weaker. You might
// not be able to retrieve data in it, if there was a buffer wrap-around or
// an very old mid-preempted entry-writing threads gets scheduled again and
// corrupts the area you just acquired. That is, you might not be able to
// retrieve certain string, but older ones might still be accessible.
// In very rare cases you could also see corrupted data in the strings!
//
// These words of warning spoken: Such data loss should be negligible if you
// make the buffer structures large enough, and read often enough from them.
#include "hal.h"
//////////////////////////////////////////////////////////////// Image Loader.
//
#define min(a, b) ((a < b) ? a : b)
struct indexEntry {
union {
volatile UINT64 data;
struct {
volatile UINT32 lo;
volatile UINT32 hi;
} hi_lo;
struct {
// use similar types to really get a packed bitfield
// (circumvent compiler limitation)
volatile UINT64 index:16; // index (lo. 16 bits) \_ 'data' grows
volatile UINT64 counter:48; // counter (hi. 48 bits) / monotonically
} val;
};
};
struct buffer_t {
indexEntry head; // head (most current) index entry
indexEntry tail; // tail (oldest valid) index entry
UINT32 flags; // 0 == monitoring active, 1 == mon. inactive
UINT32 entries; // number of elements in the following arrays
indexEntry * index; // index array
Struct_Microsoft_Singularity_Monitoring_LogEntry * logs; // entry array
uint8 * txt; // start of text area
uint8 * txtLimit; // end of text area
// fixme: we need a version number here for ABA problem
uint8 * txtCurrent; // pointer to current position in text area
UINT32 magic; // just for padding to 48 byte size
};
static unsigned char cas64(void *dest, void *comp, void *exch)
{
unsigned char retval;
__asm {
mov esi, [comp];
mov eax, [esi + 0];
mov edx, [esi + 4];
mov esi, [exch];
mov ebx, [esi + 0];
mov ecx, [esi + 4];
mov esi, [dest];
lock cmpxchg8b [esi];
sete retval;
}
return retval;
}
static unsigned char cas(void *dest, void *comp, void *exch)
{
unsigned char retval;
__asm {
mov ecx, dest;
mov edx, exch;
mov eax, comp;
lock cmpxchg [ecx], edx;
sete retval;
}
return retval;
}
// debug version that puts a seqno in _eip.
// #define GET_EIP() \
// { \
// uintptr old_seq; \
// uintptr new_seq; \
// UINT32 *valp = &(((buffer_t*)c_buffer)->magic); \
// do \
// { \
// old_seq = *valp; \
// new_seq = old_seq + 1; \
// } while (!cas(valp, (void*)old_seq, (void*)new_seq)); \
// _eip = new_seq; \
// }
#define MONITORING_BUFFER_SIZE (6 * 1024 * 1024)
#define MONITORING_TEXT_SIZE (2 * 1024 * 1024)
void
Class_Microsoft_Singularity_Monitoring::
g_Initialize()
{
#if SINGULARITY_KERNEL
// Init. all data only in the kernel
//Propagate information to userland to init. a (simpler) copy object there
// layout the header structure at the start of KERNEL_MONREC_BEGIN
g_InitPages((UIntPtr)(MONITORING_BUFFER_SIZE));
if (c_buffer == NULL) {
printf("Monitoring: Error getting Memory for buffer!!!\n");
// fixme: halt system here
return;
}
else {
printf("Monitoring: Got Memory for buffer: %p\n", c_buffer);
}
// text stuff
((buffer_t *)c_buffer)->txt =
(uint8 *) g_InitText((UIntPtr)(MONITORING_TEXT_SIZE));
if (((buffer_t *)c_buffer)->txt == NULL) {
printf("Monitoring: Error getting Memory for text!!!\n");
// fixme: halt system here
return;
}
else {
printf("Monitoring: Got Memory for text: %p\n",
((buffer_t *)c_buffer)->txt);
}
((buffer_t *)c_buffer)->txtLimit = ((buffer_t *)c_buffer)->txt +
MONITORING_TEXT_SIZE;
((buffer_t *)c_buffer)->txtCurrent = ((buffer_t *)c_buffer)->txt;
((buffer_t *)c_buffer)->head.data = 0;
((buffer_t *)c_buffer)->tail.data = 0;
((buffer_t *)c_buffer)->flags = 0;
((buffer_t *)c_buffer)->index = (indexEntry *)(((buffer_t *)c_buffer) + 1);
// compute the number of available events
// fixme: one should really have ssize_t here
int memSize = MONITORING_BUFFER_SIZE - sizeof(buffer_t);
if (memSize < sizeof(indexEntry) + sizeof(buffer_t)) {
printf("Error: Not enough memory for monitoring events!\n");
// fixme: stop machine here or something
((buffer_t *)c_buffer)->entries = 0;
}
else {
((buffer_t *)c_buffer)->entries =
min(0xffff, memSize / (sizeof(indexEntry) + sizeof(buffer_t)));
printf("Info: Monitoring will use %u entries at %p, memSize = %d.\n",
((buffer_t *)c_buffer)->entries, c_buffer, memSize);
}
((buffer_t *)c_buffer)->logs =
(Struct_Microsoft_Singularity_Monitoring_LogEntry *)
(((buffer_t *)c_buffer)->index + ((buffer_t *)c_buffer)->entries);
// init. elements
for (UINT16 i = 0; i < ((buffer_t *)c_buffer)->entries; i++) {
// clean up indices
((buffer_t *)c_buffer)->index[i].val.index = i;
((buffer_t *)c_buffer)->index[i].val.counter = i; // fixme: 0 or i
// cleanup timestamps in real entries as this is used to detect a
// valid entry
((buffer_t *)c_buffer)->logs[i].cycleCount = 0ULL;
}
// init. head and tail indices
// fixme: get this right
((buffer_t *)c_buffer)->head.val.index = 0;
((buffer_t *)c_buffer)->head.val.counter = ((buffer_t *)c_buffer)->entries;
((buffer_t *)c_buffer)->tail.val.index = 0;
((buffer_t *)c_buffer)->tail.val.counter = 0;
// last magic values, mostly used for alignment
((buffer_t *)c_buffer)->magic = 0x12345678;
#elif SINGULARITY_PROCESS
// get the address from the kernel and init. our local object
uint8 * _buffer;
Struct_Microsoft_Singularity_V1_Services_ProcessService::
g_GetMonitoringHeaders(&_buffer);
c_buffer = _buffer;
#endif
}
// Get Pointer to (hopefully dequeued) LogEntry for index into the log array
// as returned by dequeue.
Struct_Microsoft_Singularity_Monitoring_LogEntry *
Class_Microsoft_Singularity_Monitoring::
g_IndexToPointer(UINT16 index)
{
return &((buffer_t *)c_buffer)->logs[index];
}
// fixme: care for failing dequeuing due to missing elements
UINT16
Class_Microsoft_Singularity_Monitoring::
g_Dequeue()
{
indexEntry tail;
indexEntry new_tail;
UINT16 index;
// comments are from the paper where this buffer is described:
// "A Generalized Approach to Runtime Monitoring for Real-Time Systems",
// Torvald Riegel, 2005, Technische Universit<69>t Dresden, Germany
//
// 1. The tail position is read. The technique explained in the previous
// subsection (reading the higher, the lower, and again the higher word) can
// be reused if the index part is not monotonically increasing because the
// element counter part is strictly monotonically increasing and located in
// the upper 48 bits of 64 bit wide tail position. If the first and the
// second read of the higher word returned different values, this step is
// executed again.
for (;;) {
// read atomically
tail.hi_lo.hi = ((buffer_t *)c_buffer)->tail.hi_lo.hi;
tail.hi_lo.lo = ((buffer_t *)c_buffer)->tail.hi_lo.lo;
if (tail.hi_lo.hi != ((buffer_t *)c_buffer)->tail.hi_lo.hi) {
continue; // try again
}
new_tail.data = tail.data;
// 2. The element counter part and the index part of the local copy of
// the read position are advanced.
//
new_tail.val.counter++;
new_tail.val.index++;
if (new_tail.val.index >= ((buffer_t *)c_buffer)->entries) {
new_tail.val.index = 0;
}
index = tail.val.index;
// 3. Using a compare-and-exchange instruction, it is tried to
// exchange the tail position in the output buffer with the
// modified local copy. If the exchange fails because the value
// in the buffer has been modified, the algorithm is restarted at
// step one. If the operation succeeds, the index that was read
// in step one returned. It points to the dequeued and thus
// allocated output element.
//
if (cas64(&(((buffer_t *)c_buffer)->tail),
(void *)&tail.data, (void *)&new_tail.data)) {
return index;
}
}
}
void
Class_Microsoft_Singularity_Monitoring::
g_Enqueue(UINT16 newElement)
{
indexEntry head;
indexEntry new_head;
indexEntry index;
indexEntry new_index;
UINT32 i;
int enqueued;
do {
// step 1
// read atomically
head.hi_lo.hi = ((buffer_t *)c_buffer)->head.hi_lo.hi;
head.hi_lo.lo = ((buffer_t *)c_buffer)->head.hi_lo.lo;
if (head.hi_lo.hi != ((buffer_t *)c_buffer)->head.hi_lo.hi) {
continue; // try again
}
i = head.val.index;
// step 2
index.hi_lo.hi = ((buffer_t *)c_buffer)->index[i].hi_lo.hi;
index.hi_lo.lo = ((buffer_t *)c_buffer)->index[i].hi_lo.lo;
if ((index.hi_lo.hi != ((buffer_t *)c_buffer)->index[i].hi_lo.hi)
|| (index.val.counter > head.val.counter)) {
continue; // try again
}
if (index.val.counter != head.val.counter) {
// step 3
((buffer_t *)c_buffer)->logs[newElement].cycleCount = RDTSC();
// step 4
new_index.val.counter = head.val.counter;
new_index.val.index = newElement;
enqueued = cas64(&(((buffer_t *)c_buffer)->index[i]),
(void *)&index.data, (void *)&new_index.data);
}
// step 5
new_head.val.counter = head.val.counter + 1;
new_head.val.index = head.val.index + 1;
if (new_head.val.index >= ((buffer_t *)c_buffer)->entries) {
new_head.val.index = 0;
}
cas64(&(((buffer_t *)c_buffer)->head), (void *)&head.data,
(void *)&new_head.data);
} while (!enqueued);
}
void
Class_Microsoft_Singularity_Monitoring::
g_Enqueue(UINT16 newElement, UINT64 * ptr)
{
indexEntry head;
indexEntry new_head;
indexEntry index;
indexEntry new_index;
UINT32 i;
int enqueued;
do {
// step 1
// read atomically
head.hi_lo.hi = ((buffer_t *)c_buffer)->head.hi_lo.hi;
head.hi_lo.lo = ((buffer_t *)c_buffer)->head.hi_lo.lo;
if (head.hi_lo.hi != ((buffer_t *)c_buffer)->head.hi_lo.hi) {
continue; // try again
}
i = head.val.index;
// step 2
index.hi_lo.hi = ((buffer_t *)c_buffer)->index[i].hi_lo.hi;
index.hi_lo.lo = ((buffer_t *)c_buffer)->index[i].hi_lo.lo;
if ((index.hi_lo.hi != ((buffer_t *)c_buffer)->index[i].hi_lo.hi)
|| (index.val.counter > head.val.counter)) {
continue; // try again
}
if (index.val.counter != head.val.counter) {
// step 3
*ptr = RDTSC();
((buffer_t *)c_buffer)->logs[newElement].cycleCount = *ptr;
// step 4
new_index.val.counter = head.val.counter;
new_index.val.index = newElement;
enqueued = cas64(&(((buffer_t *)c_buffer)->index[i]),
(void *)&index.data, (void *)&new_index.data);
}
// step 5
new_head.val.counter = head.val.counter + 1;
new_head.val.index = head.val.index + 1;
if (new_head.val.index >= ((buffer_t *)c_buffer)->entries) {
new_head.val.index = 0;
}
cas64(&(((buffer_t *)c_buffer)->head), (void *)&head.data,
(void *)&new_head.data);
} while (!enqueued);
}
void
Class_Microsoft_Singularity_Monitoring::
g_Finalize()
{
}
uint8 *
Class_Microsoft_Singularity_Monitoring::
g_CompareExchange(uint8 **dest, uint8 *exch, uint8 *comp)
{
uint8 *val;
__asm {
mov ecx, dest;
mov edx, exch;
mov eax, comp;
lock cmpxchg [ecx], edx;
mov val, eax;
}
return val;
}
Struct_Microsoft_Singularity_Monitoring_LogEntry *
Class_Microsoft_Singularity_Monitoring::
g_CompareExchange(Struct_Microsoft_Singularity_Monitoring_LogEntry **dest,
Struct_Microsoft_Singularity_Monitoring_LogEntry *exch,
Struct_Microsoft_Singularity_Monitoring_LogEntry *comp)
{
Struct_Microsoft_Singularity_Monitoring_LogEntry * val;
__asm {
mov ecx, dest;
mov edx, exch;
mov eax, comp;
lock cmpxchg [ecx], edx;
mov val, eax;
}
return val;
}
void Class_Microsoft_Singularity_Monitoring::
g_Log(uint16 provider, uint16 type, uint16 version,
uint32 a0, uint32 a1, uint32 a2, uint32 a3, uint32 a4)
{
// fixme: should we check for c_buffer != 0 ???
if (! g_isActive()) {
return;
}
uintptr _eip;
__asm {
mov eax, [ebp+4];
mov _eip, eax;
}
UINT16 index;
Struct_Microsoft_Singularity_Monitoring_LogEntry * p;
Struct_Microsoft_Singularity_X86_ThreadContext *threadContext =
Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext();
int cpuid = Class_Microsoft_Singularity_Processor::
g_GetCurrentProcessorContext()->cpuId;
// get buffer
index = g_Dequeue();
p = g_IndexToPointer(index);
// fill it
p->eip = _eip;
p->provider = provider;
p->type = type;
p->text = NULL;
p->cpu = cpuid;
p->version = version;
p->arg0 = a0;
p->arg1 = a1;
p->arg2 = a2;
p->arg3 = a3;
p->arg4 = a4;
p->processId = threadContext->processId;
#ifdef SINGULARITY_KERNEL
p->threadId = threadContext->threadIndex;
#else
p->threadId = threadContext->kernelThreadIndex;
#endif
// return buffer
g_Enqueue(index);
// UINT32 d_ret;
// d_ret = g_ConsistencyCheck();
// if (d_ret) {
// Class_Microsoft_Singularity_DebugStub::g_Break();
// }
}
void Class_Microsoft_Singularity_Monitoring::
g_Log(uint16 provider, uint16 type)
{
// fixme: should we check for c_buffer != 0 ??? Right now we assume to
// only get called after init.
if (! g_isActive()) {
return;
}
uintptr _eip;
__asm {
mov eax, [ebp+4];
mov _eip, eax;
}
UINT16 index;
Struct_Microsoft_Singularity_Monitoring_LogEntry * p;
Struct_Microsoft_Singularity_X86_ThreadContext *threadContext =
Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext();
int cpuid = Class_Microsoft_Singularity_Processor::
g_GetCurrentProcessorContext()->cpuId;
// get buffer
index = g_Dequeue();
p = g_IndexToPointer(index);
// fill it
p->eip = _eip;
p->provider = provider;
p->type = type;
p->text = NULL;
p->cpu = cpuid;
p->version = 0;
p->arg0 = 0;
p->arg1 = 0;
p->arg2 = 0;
p->arg3 = 0;
p->arg4 = 0;
p->processId = threadContext->processId;
#ifdef SINGULARITY_KERNEL
p->threadId = threadContext->threadIndex;
#else
p->threadId = threadContext->kernelThreadIndex;
#endif
// return buffer
g_Enqueue(index);
// UINT32 d_ret;
// d_ret = g_ConsistencyCheck();
// if (d_ret) {
// Class_Microsoft_Singularity_DebugStub::g_Break();
// }
}
void Class_Microsoft_Singularity_Monitoring::
g_Log(uint16 provider, uint16 type, Class_System_String *s)
{
// fixme: should we check for c_buffer != 0 ??? Right now we assume to
// only get called after init.
if (! g_isActive()) {
return;
}
uintptr _eip;
__asm {
mov eax, [ebp+4];
mov _eip, eax;
}
UINT16 index;
Struct_Microsoft_Singularity_Monitoring_LogEntry * p;
Struct_Microsoft_Singularity_X86_ThreadContext *threadContext =
Class_Microsoft_Singularity_Processor::g_GetCurrentThreadContext();
int cpuid = Class_Microsoft_Singularity_Processor::
g_GetCurrentProcessorContext()->cpuId;
// get buffer
index = g_Dequeue();
p = g_IndexToPointer(index);
// fill it
p->eip = _eip;
p->provider = provider;
p->type = type;
p->cpu = cpuid;
p->version = 0;
p->arg0 = 0;
p->arg1 = 0;
p->arg2 = 0;
p->arg3 = 0;
p->arg4 = 0;
p->processId = threadContext->processId;
#ifdef SINGULARITY_KERNEL
p->threadId = threadContext->threadIndex;
#else
p->threadId = threadContext->kernelThreadIndex;
#endif
// care for the string now ...
bool enabled = Class_Microsoft_Singularity_Processor::g_DisableInterrupts();
// reserve space for one 64 bit counter, 32 bit for the string length and
// the string itself
uint8 * newTxt;
uint8 * oldTxt;
// Class_Microsoft_Singularity_DebugStub::g_Break();
// update txtCurrent, align to 8 byte
do {
oldTxt = ((buffer_t *)c_buffer)->txtCurrent;
// well, this is ugly but /W3 seems to prevent bitmasking (uint8 *) ...
newTxt = (uint8 *)((unsigned)
((oldTxt + sizeof(UINT64) + sizeof(UINT32) +
s->m_stringLength + 7)) & ((unsigned)(-1) - 7));
if (newTxt >= ((buffer_t *)c_buffer)->txtLimit) {
newTxt = (uint8 *)((unsigned)
(((buffer_t *)c_buffer)->txt + sizeof(UINT64) +
sizeof(UINT32) + s->m_stringLength + 7) &
((unsigned)(-1) - 7));
}
} while (! cas(&((buffer_t *)c_buffer)->txtCurrent, oldTxt, newTxt));
*(oldTxt + sizeof(UINT64)) = s->m_stringLength; // write length
g_AddText(oldTxt + sizeof(UINT64) + sizeof(UINT32), s); // write string
p->text = oldTxt; // string ptr -> event
// return buffer
// also sets counter in string, *before* releasing event
g_Enqueue(index, (UINT64 *)oldTxt);
Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(enabled);
// UINT32 d_ret;
// d_ret = g_ConsistencyCheck();
// if (d_ret) {
// Class_Microsoft_Singularity_DebugStub::g_Break();
// }
}
int Class_Microsoft_Singularity_Monitoring::
g_FillLogEntry(Struct_Microsoft_Singularity_Monitoring_LogEntry * log,
UINT64 * min_counter)
{
// fixme: should we check for c_buffer != 0 ???, probably not necessary,
// Initialize() should have been called long before first request
// here, right?
indexEntry tail;
indexEntry head;
indexEntry ie;
UINT16 index;
// UINT32 d_ret;
// d_ret = g_ConsistencyCheck();
// if (d_ret) {
// Class_Microsoft_Singularity_DebugStub::g_Break();
// }
// get tail pointer first
do {
tail.hi_lo.hi = ((buffer_t *)c_buffer)->tail.hi_lo.hi;
tail.hi_lo.lo = ((buffer_t *)c_buffer)->tail.hi_lo.lo;
} while (tail.hi_lo.hi != ((buffer_t *)c_buffer)->tail.hi_lo.hi);
for (;;) {
// check if user wants valid entry, no? give him the oldest valid one
if (*min_counter < tail.val.counter) {
*min_counter = tail.val.counter;
}
// check for too fast request polling
do {
head.hi_lo.hi = ((buffer_t *)c_buffer)->head.hi_lo.hi;
head.hi_lo.lo = ((buffer_t *)c_buffer)->head.hi_lo.lo;
} while (head.hi_lo.hi != ((buffer_t *)c_buffer)->head.hi_lo.hi);
// consumer requests counter in the future
if (*min_counter >= head.val.counter) {
return -1;
}
// now get the index entry atomically
index = (UINT16)(*min_counter % ((buffer_t *)c_buffer)->entries);
do {
ie.hi_lo.hi = ((buffer_t *)c_buffer)->index[index].hi_lo.hi;
ie.hi_lo.lo = ((buffer_t *)c_buffer)->index[index].hi_lo.lo;
} while (ie.hi_lo.hi != ((buffer_t *)c_buffer)->index[index].hi_lo.hi);
// if index is newer than expected, try again
if (ie.val.counter != *min_counter) {
continue;
}
// now copy the whole thing
*log = ((buffer_t *)c_buffer)->logs[ie.val.index];
// get tail pointer again
do {
tail.hi_lo.hi = ((buffer_t *)c_buffer)->tail.hi_lo.hi;
tail.hi_lo.lo = ((buffer_t *)c_buffer)->tail.hi_lo.lo;
} while (tail.hi_lo.hi != ((buffer_t *)c_buffer)->tail.hi_lo.hi);
// check if we were overtaken
if (tail.val.counter <= *min_counter) {
break; // finally, we got it ...
}
}
// d_ret = g_ConsistencyCheck();
// if (d_ret) {
// Class_Microsoft_Singularity_DebugStub::g_Break();
// }
return 0;
}
int Class_Microsoft_Singularity_Monitoring::
g_FillTextEntry(uint8 * src, UINT64 counter, uint8 * dst, int max_size)
{
uint8 * old_src = src;
if ((src < ((buffer_t *)c_buffer)->txt) ||
(src + sizeof(UINT64) + sizeof(UINT32) >
((buffer_t *)c_buffer)->txtLimit)) {
return -2; // memory bounds error
}
// 1. get size
// fixme: make another bounds check here
int len = *(UINT32 *)(src + sizeof(UINT64));
// fixme: create a memory barrier here
// 2. check TSC, -> bail out if wrong
volatile UINT64 _counter = *(UINT64 *)(src);
if (_counter != counter) {
return -1; // corrupt data
}
src += sizeof(UINT64) + sizeof(UINT32);
// 3. copy string
int i;
for (i = 0; i < max_size && i < len; i++) {
*dst++ = *src++;
}
// 4. check TSC again, -> bail out if wrong
_counter = *(UINT64 *)(old_src);
if (_counter != counter) {
return -3; // corrupt data
}
return i;
}
// Copies a given string to a memory area by stripping every second byte,
// UTF16 -> ASCII conversion, assuming there where no control characters in the
// UTF16 string ...
uint8 * Class_Microsoft_Singularity_Monitoring::
g_AddText(uint8 *dst, Class_System_String *arg)
{
bartok_char *src = &arg->m_firstChar;
bartok_char *end = src + arg->m_stringLength;
while (src < end) {
*dst++ = (uint8)*src++;
}
// *dst++ = '\0';
return dst;
}
bool Class_Microsoft_Singularity_Monitoring::
g_isActive()
{
return ((buffer_t *)c_buffer)->flags == 0;
}
void Class_Microsoft_Singularity_Monitoring::
g_setActive(bool active)
{
if (active) {
((buffer_t *)c_buffer)->flags = 0;
}
else {
((buffer_t *)c_buffer)->flags = 1;
}
}
void Class_Microsoft_Singularity_Monitoring::
g_DebugTest(UINT64 * h_ts, UINT64 * t_ts, UINT64 *min, UINT64 * max)
{
// output head and tail counters
#if 0
#if SINGULARITY_KERNEL
printf("Head (%llu, %llu), Tail (%llu, %llu)\n",
((buffer_t *)c_buffer)->head.val.index, ((buffer_t *)c_buffer)->head.val.counter,
((buffer_t *)c_buffer)->tail.val.index, ((buffer_t *)c_buffer)->tail.val.counter);
#else
Class_Microsoft_Singularity_DebugStub::Print("Head (" + ((buffer_t *)c_buffer)->head.val.index +
", " + ((buffer_t *)c_buffer)->head.val.counter +
"), Tail (" + ((buffer_t *)c_buffer)->tail.val.index +
", " + ((buffer_t *)c_buffer)->tail.val.counter) + ")\n");
#endif
#endif
// output head and tail elements
UINT64 ih, it;
UINT64 ih2, it2;
ih = (((buffer_t *)c_buffer)->head.val.counter - 1) % ((buffer_t *)c_buffer)->entries;
it = (((buffer_t *)c_buffer)->tail.val.counter) % ((buffer_t *)c_buffer)->entries;
ih2 = ((buffer_t *)c_buffer)->index[ih].val.index;
it2 = ((buffer_t *)c_buffer)->index[it].val.index;
#if 0
#if SINGULARITY_KERNEL
printf("TS: Head-1 (%llu), Tail (%llu)\n",
((buffer_t *)c_buffer)->logs[ih2].cycleCount,
((buffer_t *)c_buffer)->logs[it2].cycleCount);
#else
Class_Microsoft_Singularity_DebugStub::Print("TS: Head-1 (" + ((buffer_t *)c_buffer)->logs[ih2].cycleCount +
"), Tail (" + ((buffer_t *)c_buffer)->logs[it2].cycleCount + ")\n");
#endif
#endif
*h_ts = ((buffer_t *)c_buffer)->logs[ih2].cycleCount;
*t_ts = ((buffer_t *)c_buffer)->logs[it2].cycleCount;
// show min and max ts + its index
UINT32 i, j;
UINT64 min_ts = 100000000000ULL, max_ts = 0, ts;
for (i = ((buffer_t *)c_buffer)->tail.val.counter;
i < ((buffer_t *)c_buffer)->head.val.counter;) {
j = i % ((buffer_t *)c_buffer)->entries;
ts = ((buffer_t *)c_buffer)->logs[((buffer_t *)c_buffer)->index[j].val.index].cycleCount;
if (ts < min_ts) {
min_ts = ts;
}
if (ts > max_ts) {
max_ts = ts;
}
// advance i
i++;
if (i >= ((buffer_t *)c_buffer)->entries) {
i = 0;
}
}
#if 0
#if SINGULARITY_KERNEL
printf("TS: Min (%llu), Max (%llu)\n", min_ts, max_ts);
#else
Class_Microsoft_Singularity_DebugStub::Print("TS: Min (" + min_ts + "), Max (" +max_ts + ")\n");
#endif
#endif
*min = min_ts;
*max = max_ts;
}
uint32 Class_Microsoft_Singularity_Monitoring::
g_ConsistencyCheck()
{
bool id;
id = Class_Microsoft_Singularity_Processor::g_DisableInterrupts();
// run through all indices and check the TSs of the log entries for
// ascending order
uint64 i;
uint32 j;
uint32 k = 0;
uint64 old_ts = 0;
uint64 ts;
for (i = ((buffer_t *)c_buffer)->tail.val.counter;
i < ((buffer_t *)c_buffer)->head.val.counter;
i++, k++) {
j = (UINT32)(i % ((buffer_t *)c_buffer)->entries);
ts = ((buffer_t *)c_buffer)->logs[((buffer_t *)c_buffer)->index[j].val.index].cycleCount;
if (ts < old_ts && old_ts != 0 && ts != 0) {
((buffer_t *)c_buffer)->magic = (UINT32)i;
Class_Microsoft_Singularity_DebugStub::g_Break();
Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(id);
return (UINT32)i;
}
old_ts = ts;
if (k > 100000) {
Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(id);
Class_Microsoft_Singularity_DebugStub::g_Break();
return 0;
}
}
Class_Microsoft_Singularity_Processor::g_RestoreInterrupts(id);
return 0; // everything is fine!
}
//
///////////////////////////////////////////////////////////////// End of File.