Commit 5a2769f0 authored by Simon Marlow's avatar Simon Marlow

New tracing interface

A simple interface for generating trace messages with timestamps and
thread IDs attached to them.  Most debugging output goes through this
interface now, so it is straightforward to get timestamped debugging
traces with +RTS -vt.  Also, we plan to use this to generate
parallelism profiles from the trace output.
parent 3f10646c
......@@ -25,6 +25,7 @@
#include "Capability.h"
#include "Schedule.h"
#include "Sparks.h"
#include "Trace.h"
// one global capability, this is the Capability for non-threaded
// builds, and for +RTS -N1
......@@ -196,8 +197,7 @@ initCapabilities( void )
initCapability(&capabilities[i], i);
}
IF_DEBUG(scheduler, sched_belch("allocated %d capabilities",
n_capabilities));
debugTrace(DEBUG_sched, "allocated %d capabilities", n_capabilities);
#else /* !THREADED_RTS */
......@@ -233,10 +233,10 @@ giveCapabilityToTask (Capability *cap USED_IF_DEBUG, Task *task)
{
ASSERT_LOCK_HELD(&cap->lock);
ASSERT(task->cap == cap);
IF_DEBUG(scheduler,
sched_belch("passing capability %d to %s %p",
cap->no, task->tso ? "bound task" : "worker",
(void *)task->id));
trace(TRACE_sched | DEBUG_sched,
"passing capability %d to %s %p",
cap->no, task->tso ? "bound task" : "worker",
(void *)task->id);
ACQUIRE_LOCK(&task->lock);
task->wakeup = rtsTrue;
// the wakeup flag is needed because signalCondition() doesn't
......@@ -291,8 +291,8 @@ releaseCapability_ (Capability* cap)
// are threads that need to be completed. If the system is
// shutting down, we never create a new worker.
if (sched_state < SCHED_SHUTTING_DOWN || !emptyRunQueue(cap)) {
IF_DEBUG(scheduler,
sched_belch("starting new worker on capability %d", cap->no));
debugTrace(DEBUG_sched,
"starting new worker on capability %d", cap->no);
startWorkerTask(cap, workerStart);
return;
}
......@@ -310,7 +310,7 @@ releaseCapability_ (Capability* cap)
}
last_free_capability = cap;
IF_DEBUG(scheduler, sched_belch("freeing capability %d", cap->no));
trace(TRACE_sched | DEBUG_sched, "freeing capability %d", cap->no);
}
void
......@@ -396,8 +396,7 @@ waitForReturnCapability (Capability **pCap, Task *task)
ACQUIRE_LOCK(&cap->lock);
IF_DEBUG(scheduler,
sched_belch("returning; I want capability %d", cap->no));
debugTrace(DEBUG_sched, "returning; I want capability %d", cap->no);
if (!cap->running_task) {
// It's free; just grab it
......@@ -435,8 +434,7 @@ waitForReturnCapability (Capability **pCap, Task *task)
ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);
IF_DEBUG(scheduler,
sched_belch("returning; got capability %d", cap->no));
trace(TRACE_sched | DEBUG_sched, "resuming capability %d", cap->no);
*pCap = cap;
#endif
......@@ -455,7 +453,7 @@ yieldCapability (Capability** pCap, Task *task)
// The fast path has no locking, if we don't enter this while loop
while ( cap->returning_tasks_hd != NULL || !anyWorkForMe(cap,task) ) {
IF_DEBUG(scheduler, sched_belch("giving up capability %d", cap->no));
debugTrace(DEBUG_sched, "giving up capability %d", cap->no);
// We must now release the capability and wait to be woken up
// again.
......@@ -470,10 +468,12 @@ yieldCapability (Capability** pCap, Task *task)
task->wakeup = rtsFalse;
RELEASE_LOCK(&task->lock);
IF_DEBUG(scheduler, sched_belch("woken up on capability %d", cap->no));
debugTrace(DEBUG_sched, "woken up on capability %d", cap->no);
ACQUIRE_LOCK(&cap->lock);
if (cap->running_task != NULL) {
IF_DEBUG(scheduler, sched_belch("capability %d is owned by another task", cap->no));
debugTrace(DEBUG_sched,
"capability %d is owned by another task", cap->no);
RELEASE_LOCK(&cap->lock);
continue;
}
......@@ -495,7 +495,7 @@ yieldCapability (Capability** pCap, Task *task)
break;
}
IF_DEBUG(scheduler, sched_belch("got capability %d", cap->no));
trace(TRACE_sched | DEBUG_sched, "resuming capability %d", cap->no);
ASSERT(cap->running_task == task);
}
......@@ -527,6 +527,7 @@ wakeupThreadOnCapability (Capability *cap, StgTSO *tso)
// start it up
cap->running_task = myTask(); // precond for releaseCapability_()
trace(TRACE_sched, "resuming capability %d", cap->no);
releaseCapability_(cap);
} else {
appendToWakeupQueue(cap,tso);
......@@ -557,6 +558,7 @@ prodCapabilities(rtsBool all)
ACQUIRE_LOCK(&cap->lock);
if (!cap->running_task) {
if (cap->spare_workers) {
trace(TRACE_sched, "resuming capability %d", cap->no);
task = cap->spare_workers;
ASSERT(!task->stopped);
giveCapabilityToTask(cap,task);
......@@ -616,23 +618,25 @@ shutdownCapability (Capability *cap, Task *task)
task->cap = cap;
for (i = 0; i < 50; i++) {
IF_DEBUG(scheduler, sched_belch("shutting down capability %d, attempt %d", cap->no, i));
debugTrace(DEBUG_sched,
"shutting down capability %d, attempt %d", cap->no, i);
ACQUIRE_LOCK(&cap->lock);
if (cap->running_task) {
RELEASE_LOCK(&cap->lock);
IF_DEBUG(scheduler, sched_belch("not owner, yielding"));
debugTrace(DEBUG_sched, "not owner, yielding");
yieldThread();
continue;
}
cap->running_task = task;
if (!emptyRunQueue(cap) || cap->spare_workers) {
IF_DEBUG(scheduler, sched_belch("runnable threads or workers still alive, yielding"));
debugTrace(DEBUG_sched,
"runnable threads or workers still alive, yielding");
releaseCapability_(cap); // this will wake up a worker
RELEASE_LOCK(&cap->lock);
yieldThread();
continue;
}
IF_DEBUG(scheduler, sched_belch("capability %d is stopped.", cap->no));
debugTrace(DEBUG_sched, "capability %d is stopped.", cap->no);
RELEASE_LOCK(&cap->lock);
break;
}
......
This diff is collapsed.
......@@ -17,6 +17,7 @@
#include "GCCompact.h"
#include "Schedule.h"
#include "Apply.h"
#include "Trace.h"
// Turn off inlining when debugging - it obfuscates things
#ifdef DEBUG
......@@ -931,12 +932,14 @@ compact( void (*get_roots)(evac_fn) )
for (s = 0; s < generations[g].n_steps; s++) {
if (g==0 && s ==0) continue;
stp = &generations[g].steps[s];
IF_DEBUG(gc, debugBelch("update_fwd: %d.%d\n", stp->gen->no, stp->no););
debugTrace(DEBUG_gc, "update_fwd: %d.%d",
stp->gen->no, stp->no);
update_fwd(stp->blocks);
update_fwd_large(stp->scavenged_large_objects);
if (g == RtsFlags.GcFlags.generations-1 && stp->old_blocks != NULL) {
IF_DEBUG(gc, debugBelch("update_fwd: %d.%d (compact)\n", stp->gen->no, stp->no););
debugTrace(DEBUG_gc, "update_fwd: %d.%d (compact)",
stp->gen->no, stp->no);
update_fwd_compact(stp->old_blocks);
}
}
......@@ -946,9 +949,10 @@ compact( void (*get_roots)(evac_fn) )
stp = &oldest_gen->steps[0];
if (stp->old_blocks != NULL) {
blocks = update_bkwd_compact(stp);
IF_DEBUG(gc, debugBelch("update_bkwd: %d.%d (compact, old: %d blocks, now %d blocks)\n",
stp->gen->no, stp->no,
stp->n_old_blocks, blocks););
debugTrace(DEBUG_gc,
"update_bkwd: %d.%d (compact, old: %d blocks, now %d blocks)",
stp->gen->no, stp->no,
stp->n_old_blocks, blocks);
stp->n_old_blocks = blocks;
}
}
......@@ -16,6 +16,7 @@
#include "RtsFlags.h"
#include "MBlock.h"
#include "BlockAlloc.h"
#include "Trace.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
......@@ -287,7 +288,7 @@ getMBlocks(nat n)
// ToDo: check that we haven't already grabbed the memory at next_request
next_request = ret + size;
IF_DEBUG(gc,debugBelch("Allocated %d megablock(s) at %p\n",n,ret));
debugTrace(DEBUG_gc, "allocated %d megablock(s) at %p",n,ret);
// fill in the table
for (i = 0; i < n; i++) {
......@@ -402,7 +403,7 @@ getMBlocks(nat n)
barf("getMBlocks: unknown memory allocation failure on Win32.");
}
IF_DEBUG(gc,debugBelch("Allocated %d megablock(s) at 0x%x\n",n,(nat)ret));
debugTrace(DEBUG_gc, "allocated %d megablock(s) at 0x%x",n,(nat)ret);
next_request = (char*)next_request + size;
mblocks_allocated += n;
......
......@@ -353,11 +353,12 @@ CostCentreStack *
PushCostCentre ( CostCentreStack *ccs, CostCentre *cc )
#define PushCostCentre _PushCostCentre
{
IF_DEBUG(prof,
debugBelch("Pushing %s on ", cc->label);
debugCCS(ccs);
debugBelch("\n"));
return PushCostCentre(ccs,cc);
IF_DEBUG(prof,
traceBegin("pushing %s on ", cc->label);
debugCCS(ccs);
traceEnd(););
return PushCostCentre(ccs,cc);
}
#endif
......
......@@ -27,6 +27,7 @@
#include "Linker.h"
#include "ThreadLabels.h"
#include "BlockAlloc.h"
#include "Trace.h"
#if defined(RTS_GTK_FRONTPANEL)
#include "FrontPanel.h"
......@@ -161,6 +162,9 @@ hs_init(int *argc, char **argv[])
setProgArgv(*argc,*argv);
}
/* initTracing must be after setupRtsFlags() */
initTracing();
#if defined(PAR)
/* NB: this really must be done after processing the RTS flags */
IF_PAR_DEBUG(verbose,
......
......@@ -90,6 +90,7 @@
#include "SMP.h"
#include "STM.h"
#include "Storage.h"
#include "Trace.h"
#include <stdlib.h>
#include <stdio.h>
......@@ -113,16 +114,7 @@
// If SHAKE is defined then validation will sometime spuriously fail. They helps test
// unusualy code paths if genuine contention is rare
#if defined(DEBUG)
#define SHAKE
#if defined(THREADED_RTS)
#define TRACE(_x...) IF_DEBUG(stm, debugBelch("STM (task %p): ", (void *)(unsigned long)(unsigned int)osThreadId()); debugBelch ( _x ))
#else
#define TRACE(_x...) IF_DEBUG(stm, debugBelch ( _x ))
#endif
#else
#define TRACE(_x...) /*Nothing*/
#endif
#define TRACE(_x...) debugTrace(DEBUG_stm, "STM: " _x)
#ifdef SHAKE
static const int do_shake = TRUE;
......
This diff is collapsed.
......@@ -314,11 +314,6 @@ emptyThreadQueues(Capability *cap)
;
}
#ifdef DEBUG
void sched_belch(char *s, ...)
GNU_ATTRIBUTE(format (printf, 1, 2));
#endif
#endif /* !IN_STG_CODE */
STATIC_INLINE void
......
......@@ -21,6 +21,7 @@
# include "GranSimRts.h"
# endif
#include "Sparks.h"
#include "Trace.h"
#if defined(THREADED_RTS) || defined(PARALLEL_HASKELL)
......@@ -149,19 +150,18 @@ markSparkQueue (evac_fn evac)
PAR_TICKY_MARK_SPARK_QUEUE_END(n);
#if defined(PARALLEL_HASKELL)
IF_DEBUG(scheduler,
debugBelch("markSparkQueue: marked %d sparks and pruned %d sparks on [%x]",
n, pruned_sparks, mytid));
debugTrace(DEBUG_sched,
"marked %d sparks and pruned %d sparks on [%x]",
n, pruned_sparks, mytid);
#else
IF_DEBUG(scheduler,
debugBelch("markSparkQueue: marked %d sparks and pruned %d sparks\n",
n, pruned_sparks));
debugTrace(DEBUG_sched,
"marked %d sparks and pruned %d sparks",
n, pruned_sparks);
#endif
IF_DEBUG(scheduler,
debugBelch("markSparkQueue: new spark queue len=%d; (hd=%p; tl=%p)\n",
sparkPoolSize(pool), pool->hd, pool->tl));
debugTrace(DEBUG_sched,
"new spark queue len=%d; (hd=%p; tl=%p)\n",
sparkPoolSize(pool), pool->hd, pool->tl);
}
}
......@@ -825,8 +825,9 @@ markSparkQueue(void)
// ToDo?: statistics gathering here (also for GUM!)
sp->node = (StgClosure *)MarkRoot(sp->node);
}
IF_DEBUG(gc,
debugBelch("@@ markSparkQueue: spark statistics at start of GC:");
debugBelch("markSparkQueue: spark statistics at start of GC:");
print_sparkq_stats());
}
......
......@@ -18,6 +18,7 @@
#include "RtsAPI.h"
#include "RtsFlags.h"
#include "OSThreads.h"
#include "Trace.h"
/* Comment from ADR's implementation in old RTS:
......@@ -199,7 +200,7 @@ lookupStableName_(StgPtr p)
if (sn != 0) {
ASSERT(stable_ptr_table[sn].addr == p);
IF_DEBUG(stable,debugBelch("cached stable name %ld at %p\n",sn,p));
debugTrace(DEBUG_stable, "cached stable name %ld at %p",sn,p);
return sn;
} else {
sn = stable_ptr_free - stable_ptr_table;
......@@ -207,7 +208,7 @@ lookupStableName_(StgPtr p)
stable_ptr_table[sn].ref = 0;
stable_ptr_table[sn].addr = p;
stable_ptr_table[sn].sn_obj = NULL;
/* IF_DEBUG(stable,debugBelch("new stable name %d at %p\n",sn,p)); */
/* debugTrace(DEBUG_stable, "new stable name %d at %p\n",sn,p); */
/* add the new stable name to the hash table */
insertHashTable(addrToStableHash, (W_)p, (void *)sn);
......@@ -399,13 +400,15 @@ gcStablePtrTable( void )
if (p->sn_obj == NULL) {
// StableName object is dead
freeStableName(p);
IF_DEBUG(stable, debugBelch("GC'd Stable name %ld\n",
p - stable_ptr_table));
debugTrace(DEBUG_stable, "GC'd Stable name %ld",
p - stable_ptr_table);
continue;
} else {
p->addr = (StgPtr)isAlive((StgClosure *)p->addr);
IF_DEBUG(stable, debugBelch("Stable name %ld still alive at %p, ref %ld\n", p - stable_ptr_table, p->addr, p->ref));
debugTrace(DEBUG_stable,
"stable name %ld still alive at %p, ref %ld\n",
p - stable_ptr_table, p->addr, p->ref);
}
}
}
......
......@@ -75,6 +75,11 @@ Ticks stat_getElapsedGCTime(void)
return GCe_tot_time;
}
Ticks stat_getElapsedTime(void)
{
return getProcessElapsedTime() - ElapsedTimeStart;
}
/* mut_user_time_during_GC() and mut_user_time()
*
* The former function can be used to get the current mutator time
......
......@@ -52,5 +52,6 @@ void statDescribeGens( void );
HsInt64 getAllocations( void );
Ticks stat_getElapsedGCTime(void);
Ticks stat_getElapsedTime(void);
#endif /* STATS_H */
......@@ -23,6 +23,7 @@
#include "Schedule.h"
#include "RetainerProfile.h" // for counting memory blocks (memInventory)
#include "OSMem.h"
#include "Trace.h"
#include <stdlib.h>
#include <string.h>
......@@ -495,15 +496,15 @@ resizeNursery ( step *stp, nat blocks )
if (nursery_blocks == blocks) return;
if (nursery_blocks < blocks) {
IF_DEBUG(gc, debugBelch("Increasing size of nursery to %d blocks\n",
blocks));
debugTrace(DEBUG_gc, "increasing size of nursery to %d blocks",
blocks);
stp->blocks = allocNursery(stp, stp->blocks, blocks-nursery_blocks);
}
else {
bdescr *next_bd;
IF_DEBUG(gc, debugBelch("Decreasing size of nursery to %d blocks\n",
blocks));
debugTrace(DEBUG_gc, "decreasing size of nursery to %d blocks",
blocks);
bd = stp->blocks;
while (nursery_blocks > blocks) {
......@@ -1005,7 +1006,7 @@ void *allocateExec (nat bytes)
bdescr *bd;
lnat pagesize = getPageSize();
bd = allocGroup(stg_max(1, pagesize / BLOCK_SIZE));
IF_DEBUG(gc, debugBelch("allocate exec block %p\n", bd->start));
debugTrace(DEBUG_gc, "allocate exec block %p", bd->start);
bd->gen_no = 0;
bd->flags = BF_EXEC;
bd->link = exec_block;
......@@ -1046,7 +1047,7 @@ void freeExec (void *addr)
// Free the block if it is empty, but not if it is the block at
// the head of the queue.
if (bd->gen_no == 0 && bd != exec_block) {
IF_DEBUG(gc, debugBelch("free exec block %p\n", bd->start));
debugTrace(DEBUG_gc, "free exec block %p", bd->start);
if (bd->u.back) {
bd->u.back->link = bd->link;
} else {
......
......@@ -17,6 +17,7 @@
#include "RtsFlags.h"
#include "Schedule.h"
#include "Hash.h"
#include "Trace.h"
#if HAVE_SIGNAL_H
#include <signal.h>
......@@ -69,7 +70,9 @@ initTaskManager (void)
void
stopTaskManager (void)
{
IF_DEBUG(scheduler, sched_belch("stopping task manager, %d tasks still running", tasksRunning));
debugTrace(DEBUG_sched,
"stopping task manager, %d tasks still running",
tasksRunning);
}
......@@ -144,7 +147,7 @@ newBoundTask (void)
taskEnter(task);
IF_DEBUG(scheduler,sched_belch("new task (taskCount: %d)", taskCount););
debugTrace(DEBUG_sched, "new task (taskCount: %d)", taskCount);
return task;
}
......@@ -168,7 +171,7 @@ boundTaskExiting (Task *task)
task_free_list = task;
RELEASE_LOCK(&sched_mutex);
IF_DEBUG(scheduler,sched_belch("task exiting"));
debugTrace(DEBUG_sched, "task exiting");
}
#ifdef THREADED_RTS
......@@ -182,7 +185,7 @@ discardTask (Task *task)
{
ASSERT_LOCK_HELD(&sched_mutex);
if (!task->stopped) {
IF_DEBUG(scheduler,sched_belch("discarding task %p", TASK_ID(task)));
debugTrace(DEBUG_sched, "discarding task %p", TASK_ID(task));
task->cap = NULL;
task->tso = NULL;
task->stopped = rtsTrue;
......@@ -275,7 +278,7 @@ startWorkerTask (Capability *cap,
barf("startTask: Can't create new task");
}
IF_DEBUG(scheduler,sched_belch("new worker task (taskCount: %d)", taskCount););
debugTrace(DEBUG_sched, "new worker task (taskCount: %d)", taskCount);
task->id = tid;
......
/* -----------------------------------------------------------------------------
*
* (c) The GHC Team 2006
*
* Debug and performance tracing
*
* ---------------------------------------------------------------------------*/
#include "Rts.h"
#include "OSThreads.h"
#include "Trace.h"
#include "RtsFlags.h"
#include "GetTime.h"
#include "Stats.h"
/*
Features we want:
- multiple log message classes
- outpout thread ID & time on each message
- thread-safe
- trace source locations?
- break into the debugger?
*/
StgWord32 classes_enabled; // not static due to inline funcs
#ifdef THREADED_RTS
static Mutex trace_utx;
#endif
#ifdef DEBUG
#define DEBUG_FLAG(name, class) \
if (RtsFlags.DebugFlags.name) classes_enabled |= class;
#else
#define DEBUG_FLAG(name, class) \
/* nothing */
#endif
#ifdef PAR
#define PAR_FLAG(name, class) \
if (RtsFlags.ParFlags.Debug.name) classes_enabled |= class;
#else
#define PAR_FLAG(name, class) \
/* nothing */
#endif
#ifdef GRAN
#define GRAN_FLAG(name, class) \
if (RtsFlags.GranFlags.Debug.name) classes_enabled |= class;
#else
#define GRAN_FLAG(name, class) \
/* nothing */
#endif
#define TRACE_FLAG(name, class) \
if (RtsFlags.TraceFlags.name) classes_enabled |= class;
void initTracing (void)
{
#ifdef THREADED_RTS
initMutex(&trace_utx);
#endif
DEBUG_FLAG(scheduler, DEBUG_sched);
DEBUG_FLAG(interpreter, DEBUG_interp);
DEBUG_FLAG(weak, DEBUG_weak);
DEBUG_FLAG(gccafs, DEBUG_gccafs);
DEBUG_FLAG(gc, DEBUG_gc);
DEBUG_FLAG(block_alloc, DEBUG_block_alloc);
DEBUG_FLAG(sanity, DEBUG_sanity);
DEBUG_FLAG(stable, DEBUG_stable);
DEBUG_FLAG(stm, DEBUG_stm);
DEBUG_FLAG(prof, DEBUG_prof);
DEBUG_FLAG(gran, DEBUG_gran);
DEBUG_FLAG(par, DEBUG_par);
DEBUG_FLAG(linker, DEBUG_linker);
DEBUG_FLAG(squeeze, DEBUG_squeeze);
PAR_FLAG(verbose, PAR_DEBUG_verbose);
PAR_FLAG(bq, PAR_DEBUG_bq);
PAR_FLAG(schedule, PAR_DEBUG_schedule);
PAR_FLAG(free, PAR_DEBUG_free);
PAR_FLAG(resume, PAR_DEBUG_resume);
PAR_FLAG(weight, PAR_DEBUG_weight);
PAR_FLAG(fetch, PAR_DEBUG_fetch);
PAR_FLAG(fish, PAR_DEBUG_fish);
PAR_FLAG(tables, PAR_DEBUG_tables);
PAR_FLAG(packet, PAR_DEBUG_packet);
PAR_FLAG(pack, PAR_DEBUG_pack);
PAR_FLAG(paranoia, PAR_DEBUG_paranoia);
GRAN_FLAG(event_trace, GRAN_DEBUG_event_trace);
GRAN_FLAG(event_stats, GRAN_DEBUG_event_stats);
GRAN_FLAG(bq, GRAN_DEBUG_bq);
GRAN_FLAG(pack, GRAN_DEBUG_pack);
GRAN_FLAG(checkSparkQ, GRAN_DEBUG_checkSparkQ);
GRAN_FLAG(thunkStealing, GRAN_DEBUG_thunkStealing);
GRAN_FLAG(randomSteal, GRAN_DEBUG_randomSteal);
GRAN_FLAG(findWork, GRAN_DEBUG_findWork);
GRAN_FLAG(unused, GRAN_DEBUG_unused);
GRAN_FLAG(pri, GRAN_DEBUG_pri);
GRAN_FLAG(checkLight, GRAN_DEBUG_checkLight);
GRAN_FLAG(sortedQ, GRAN_DEBUG_sortedQ);
GRAN_FLAG(blockOnFetch, GRAN_DEBUG_blockOnFetch);
GRAN_FLAG(packBuffer, GRAN_DEBUG_packBuffer);
GRAN_FLAG(blockedOnFetch_sanity, GRAN_DEBUG_BOF_sanity);
TRACE_FLAG(sched, TRACE_sched);
}
static void tracePreface (void)
{
#ifdef THREADED_RTS
debugBelch("%12lx: ", (unsigned long)osThreadId());
#endif
if (RtsFlags.TraceFlags.timestamp) {
debugBelch("%9" FMT_Word64 ": ", stat_getElapsedTime());
}
}
void trace (StgWord32 class, const char *str, ...)
{
va_list ap;
va_start(ap,str);
ACQUIRE_LOCK(&trace_utx);
if ((classes_enabled & class) != 0) {
tracePreface();
vdebugBelch(str,ap);
debugBelch("\n");
}
RELEASE_LOCK(&trace_utx);
va_end(ap);
}
void traceBegin (const char *str, ...)
{
va_list ap;
va_start(ap,str);
ACQUIRE_LOCK(&trace_utx);
tracePreface();
vdebugBelch(str,ap);
}
void traceEnd (void)
{
debugBelch("\n");
RELEASE_LOCK(&trace_utx);
}
/* -----------------------------------------------------------------------------
*
* (c) The GHC Team 2006
*
* Debug and performance tracing.
*
* This is a layer over RtsMessages, which provides for generating
* trace messages with timestamps and thread Ids attached
* automatically. Also, multiple classes of messages are supported,
* which can be enabled separately via RTS flags.
*
* All debug trace messages go through here. Additionally, we
* generate timestamped trace messages for consumption by profiling
* tools using this API.
*
* ---------------------------------------------------------------------------*/
#ifndef TRACE_H
#define TRACE_H
// -----------------------------------------------------------------------------
// Tracing functions
// -----------------------------------------------------------------------------
void initTracing (void);
// The simple way:
void trace (StgWord32 class, const char *str, ...)
GNUC3_ATTRIBUTE(format (printf, 2, 3));
// The harder way: sometimes we want to generate a trace message that
// consists of multiple components generated by different functions.
// So we provide the functionality of trace() split into 3 parts:
// - traceClass(): a check that the required class is enabled
// - traceBegin(): print the beginning of the trace message
// - traceEnd(): complete the trace message (release the lock too).
//
INLINE_HEADER rtsBool traceClass (StgWord32 class);
void traceBegin (const char *str, ...)
GNUC3_ATTRIBUTE(format (printf, 1, 2));
void traceEnd (void);
#ifdef DEBUG
#define debugTrace(class, str, ...) trace(class,str, ## __VA_ARGS__)
// variable arg macros are C99, and supported by gcc.
#define debugTraceBegin(class, str, ...) traceBegin(class,str, ## __VA_ARGS__)
#define debugTraceEnd() traceEnd()
#else
#define debugTrace(class, str, ...) /* nothing */
#define debugTraceBegin(class, str, ...) /* nothing */
#define debugTraceEnd() /* nothing */
#endif
// -----------------------------------------------------------------------------
// Message classes, these may be OR-ed together
// -----------------------------------------------------------------------------
// debugging flags, set with +RTS -D<something>
#define DEBUG_sched (1<<0)
#define DEBUG_interp (1<<1)
#define DEBUG_weak (1<<2)
#define DEBUG_gccafs (1<<3)
#define DEBUG_gc (1<<4)
#define DEBUG_block_alloc (1<<5)
#define DEBUG_sanity (1<<6)
#define DEBUG_stable (1<<7)
#define DEBUG_stm (1<<8)
#define DEBUG_prof (1<<9)
#define DEBUG_gran (1<<10)
#define DEBUG_par (1<<11)
#define DEBUG_linker (1<<12)
#define DEBUG_squeeze (1<<13)
// PAR debugging flags, set with +RTS -qD<something>
#define PAR_DEBUG_verbose (1<<14)
#define PAR_DEBUG_bq (1<<15)
#define PAR_DEBUG_schedule (1<<16)