From 015d3d46b6de2f95386a515a7d166d996a0416db Mon Sep 17 00:00:00 2001 From: Manuel M T Chakravarty Date: Sat, 12 Dec 2009 10:08:09 +0000 Subject: [PATCH] Expose all EventLog events as DTrace probes - Defines a DTrace provider, called 'HaskellEvent', that provides a probe for every event of the eventlog framework. - In contrast to the original eventlog, the DTrace probes are available in all flavours of the runtime system (DTrace probes have virtually no overhead if not enabled); when -DTRACING is defined both the regular event log as well as DTrace probes can be used. - Currently, Mac OS X only. User-space DTrace probes are implemented differently on Mac OS X than in the original DTrace implementation. Nevertheless, it shouldn't be too hard to enable these probes on other platforms, too. - Documentation is at http://hackage.haskell.org/trac/ghc/wiki/DTrace --- configure.ac | 10 ++ includes/rts/EventLogFormat.h | 3 +- mk/config.mk.in | 3 + rts/Capability.c | 11 +- rts/PrimOps.cmm | 15 +++ rts/RtsProbes.d | 62 +++++++++++ rts/RtsStartup.c | 3 + rts/Schedule.c | 22 ++-- rts/Schedule.h | 2 +- rts/Sparks.c | 2 +- rts/Threads.c | 4 +- rts/Trace.c | 18 +++- rts/Trace.h | 237 ++++++++++++++++++++++++++++++++++++++++- rts/eventlog/EventLog.c | 1 - rts/ghc.mk | 27 ++++- rts/sm/GC.c | 6 +- 16 files changed, 396 insertions(+), 30 deletions(-) create mode 100644 rts/RtsProbes.d diff --git a/configure.ac b/configure.ac index d7f4a4f..d9ca453 100644 --- a/configure.ac +++ b/configure.ac @@ -558,6 +558,16 @@ dnl ** check for patch dnl if GNU patch is named gpatch, look for it first AC_PATH_PROGS(PatchCmd,gpatch patch, patch) +dnl ** check for dtrace (currently only implemented for Mac OS X) +HaveDtrace=NO +AC_PATH_PROG(DtraceCmd,dtrace) +if test -n "$DtraceCmd"; then + if test "x$TargetOS_CPP-$TargetVendor_CPP" == "xdarwin-apple"; then + HaveDtrace=YES + fi +fi +AC_SUBST(HaveDtrace) + AC_PATH_PROG(HSCOLOUR,HsColour) # HsColour is passed to Cabal, so we need a native path if test "x$HostPlatform" = "xi386-unknown-mingw32" && \ diff --git a/includes/rts/EventLogFormat.h b/includes/rts/EventLogFormat.h index 83330da..87010ee 100644 --- a/includes/rts/EventLogFormat.h +++ b/includes/rts/EventLogFormat.h @@ -112,7 +112,7 @@ #define EVENT_GC_END 10 /* () */ #define EVENT_REQUEST_SEQ_GC 11 /* () */ #define EVENT_REQUEST_PAR_GC 12 /* () */ -#define EVENT_CREATE_SPARK_THREAD 15 /* (thread, spark_thread) */ +#define EVENT_CREATE_SPARK_THREAD 15 /* (spark_thread) */ #define EVENT_LOG_MSG 16 /* (message ...) */ #define EVENT_STARTUP 17 /* (num_capabilities) */ #define EVENT_BLOCK_MARKER 18 /* (size, end_time, capability) */ @@ -148,6 +148,7 @@ typedef StgWord64 EventTimestamp; // in nanoseconds typedef StgWord32 EventThreadID; typedef StgWord16 EventCapNo; typedef StgWord16 EventPayloadSize; // variable-size events +typedef StgWord16 EventThreadStatus; // status for EVENT_STOP_THREAD #endif diff --git a/mk/config.mk.in b/mk/config.mk.in index b436235..4b8417a 100644 --- a/mk/config.mk.in +++ b/mk/config.mk.in @@ -603,6 +603,9 @@ RANLIB = @RANLIB@ SED = @SedCmd@ SHELL = /bin/sh +HaveDtrace = @HaveDtrace@ +DTRACE = @DtraceCmd@ + LD = @LdCmd@ NM = @NmCmd@ diff --git a/rts/Capability.c b/rts/Capability.c index f4fdd70..bd781e9 100644 --- a/rts/Capability.c +++ b/rts/Capability.c @@ -98,7 +98,7 @@ findSpark (Capability *cap) cap->sparks_converted++; // Post event for running a spark from capability's own pool. - traceSchedEvent(cap, EVENT_RUN_SPARK, cap->r.rCurrentTSO, 0); + traceEventRunSpark(cap, cap->r.rCurrentTSO); return spark; } @@ -132,8 +132,7 @@ findSpark (Capability *cap) if (spark != NULL) { cap->sparks_converted++; - traceSchedEvent(cap, EVENT_STEAL_SPARK, - cap->r.rCurrentTSO, robbed->no); + traceEventStealSpark(cap, cap->r.rCurrentTSO, robbed->no); return spark; } @@ -579,9 +578,9 @@ yieldCapability (Capability** pCap, Task *task) Capability *cap = *pCap; if (waiting_for_gc == PENDING_GC_PAR) { - traceSchedEvent(cap, EVENT_GC_START, 0, 0); + traceEventGcStart(cap); gcWorkerThread(cap); - traceSchedEvent(cap, EVENT_GC_END, 0, 0); + traceEventGcEnd(cap); return; } @@ -788,7 +787,7 @@ shutdownCapability (Capability *cap, Task *task, rtsBool safe) continue; } - traceSchedEvent(cap, EVENT_SHUTDOWN, 0, 0); + traceEventShutdown(cap); RELEASE_LOCK(&cap->lock); break; } diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm index b4dfb6d..377418a 100644 --- a/rts/PrimOps.cmm +++ b/rts/PrimOps.cmm @@ -1903,8 +1903,23 @@ stg_traceEventzh { W_ msg; msg = R1; + #if defined(TRACING) || defined(DEBUG) + foreign "C" traceUserMsg(MyCapability() "ptr", msg "ptr") []; + +#elif defined(DTRACE) + + W_ enabled; + + // We should go through the macro HASKELLEVENT_USER_MSG_ENABLED from + // RtsProbes.h, but that header file includes unistd.h, which doesn't + // work in Cmm + (enabled) = foreign "C" __dtrace_isenabled$HaskellEvent$user__msg$v1() []; + if (enabled != 0) { + foreign "C" dtraceUserMsgWrapper(MyCapability() "ptr", msg "ptr") []; + } + #endif jump %ENTRY_CODE(Sp(0)); } diff --git a/rts/RtsProbes.d b/rts/RtsProbes.d new file mode 100644 index 0000000..87a34c8 --- /dev/null +++ b/rts/RtsProbes.d @@ -0,0 +1,62 @@ +/* ----------------------------------------------------------------------------- + * + * (c) The GHC Team, 2009 + * + * User-space dtrace probes for the runtime system. + * + * ---------------------------------------------------------------------------*/ + +#include "HsFFI.h" +#include "rts/EventLogFormat.h" + + +// ----------------------------------------------------------------------------- +// Payload datatypes for Haskell events +// ----------------------------------------------------------------------------- + +// We effectively have: +// +// typedef uint16_t EventTypeNum; +// typedef uint64_t EventTimestamp; // in nanoseconds +// typedef uint32_t EventThreadID; +// typedef uint16_t EventCapNo; +// typedef uint16_t EventPayloadSize; // variable-size events +// typedef uint16_t EventThreadStatus; + + +// ----------------------------------------------------------------------------- +// The HaskellEvent provider captures everything from eventlog for use with +// dtrace +// ----------------------------------------------------------------------------- + +// These probes correspond to the events defined in EventLogFormat.h +// +provider HaskellEvent { + + // scheduler events + probe create__thread (EventCapNo, EventThreadID); + probe run__thread (EventCapNo, EventThreadID); + probe stop__thread (EventCapNo, EventThreadID, EventThreadStatus); + probe thread__runnable (EventCapNo, EventThreadID); + probe migrate__thread (EventCapNo, EventThreadID, EventCapNo); + probe run__spark (EventCapNo, EventThreadID); + probe steal__spark (EventCapNo, EventThreadID, EventCapNo); + probe shutdown (EventCapNo); + probe thread_wakeup (EventCapNo, EventThreadID, EventCapNo); + probe gc__start (EventCapNo); + probe gc__end (EventCapNo); + probe request__seq__gc (EventCapNo); + probe request__par__gc (EventCapNo); + probe create__spark__thread (EventCapNo, EventThreadID); + + // other events +//This one doesn't seem to be used at all at the moment: +// probe log__msg (char *); + probe startup (EventCapNo); + // we don't need EVENT_BLOCK_MARKER with dtrace + probe user__msg (EventCapNo, char *); + probe gc__idle (EventCapNo); + probe gc__work (EventCapNo); + probe gc__done (EventCapNo); + +}; diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index afa38aa..b85b153 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -149,6 +149,9 @@ hs_init(int *argc, char **argv[]) #ifdef TRACING initTracing(); #endif + /* Dtrace events are always enabled + */ + dtraceEventStartup(); /* initialise scheduler data structures (needs to be done before * initStorage()). diff --git a/rts/Schedule.c b/rts/Schedule.c index 3f07d3c..cfdb392 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -468,7 +468,7 @@ run_thread: } #endif - traceSchedEvent(cap, EVENT_RUN_THREAD, t, 0); + traceEventRunThread(cap, t); switch (prev_what_next) { @@ -518,7 +518,7 @@ run_thread: t->saved_winerror = GetLastError(); #endif - traceSchedEvent (cap, EVENT_STOP_THREAD, t, ret); + traceEventStopThread(cap, t, ret); #if defined(THREADED_RTS) // If ret is ThreadBlocked, and this Task is bound to the TSO that @@ -778,7 +778,7 @@ schedulePushWork(Capability *cap USED_IF_THREADS, debugTrace(DEBUG_sched, "pushing thread %lu to capability %d", (unsigned long)t->id, free_caps[i]->no); appendToRunQueue(free_caps[i],t); - traceSchedEvent (cap, EVENT_MIGRATE_THREAD, t, free_caps[i]->no); + traceEventMigrateThread (cap, t, free_caps[i]->no); if (t->bound) { t->bound->cap = free_caps[i]; } t->cap = free_caps[i]; @@ -802,7 +802,7 @@ schedulePushWork(Capability *cap USED_IF_THREADS, if (spark != NULL) { debugTrace(DEBUG_sched, "pushing spark %p to capability %d", spark, free_caps[i]->no); - traceSchedEvent(free_caps[i], EVENT_STEAL_SPARK, t, cap->no); + traceEventStealSpark(free_caps[i], t, cap->no); newSpark(&(free_caps[i]->r), spark); } @@ -1418,11 +1418,11 @@ scheduleDoGC (Capability *cap, Task *task USED_IF_THREADS, rtsBool force_major) if (gc_type == PENDING_GC_SEQ) { - traceSchedEvent(cap, EVENT_REQUEST_SEQ_GC, 0, 0); + traceEventRequestSeqGc(cap); } else { - traceSchedEvent(cap, EVENT_REQUEST_PAR_GC, 0, 0); + traceEventRequestParGc(cap); debugTrace(DEBUG_sched, "ready_to_gc, grabbing GC threads"); } @@ -1478,8 +1478,8 @@ delete_threads_and_gc: heap_census = scheduleNeedHeapProfile(rtsTrue); + traceEventGcStart(cap); #if defined(THREADED_RTS) - traceSchedEvent(cap, EVENT_GC_START, 0, 0); // reset waiting_for_gc *before* GC, so that when the GC threads // emerge they don't immediately re-enter the GC. waiting_for_gc = 0; @@ -1487,7 +1487,7 @@ delete_threads_and_gc: #else GarbageCollect(force_major || heap_census, 0, cap); #endif - traceSchedEvent(cap, EVENT_GC_END, 0, 0); + traceEventGcEnd(cap); if (recent_activity == ACTIVITY_INACTIVE && force_major) { @@ -1806,7 +1806,7 @@ suspendThread (StgRegTable *reg) task = cap->running_task; tso = cap->r.rCurrentTSO; - traceSchedEvent(cap, EVENT_STOP_THREAD, tso, THREAD_SUSPENDED_FOREIGN_CALL); + traceEventStopThread(cap, tso, THREAD_SUSPENDED_FOREIGN_CALL); // XXX this might not be necessary --SDM tso->what_next = ThreadRunGHC; @@ -1869,7 +1869,7 @@ resumeThread (void *task_) task->suspended_tso = NULL; tso->_link = END_TSO_QUEUE; // no write barrier reqd - traceSchedEvent(cap, EVENT_RUN_THREAD, tso, tso->what_next); + traceEventRunThread(cap, tso); if (tso->why_blocked == BlockedOnCCall) { // avoid locking the TSO if we don't have to @@ -1925,7 +1925,7 @@ scheduleThreadOn(Capability *cap, StgWord cpu USED_IF_THREADS, StgTSO *tso) if (cpu == cap->no) { appendToRunQueue(cap,tso); } else { - traceSchedEvent (cap, EVENT_MIGRATE_THREAD, tso, capabilities[cpu].no); + traceEventMigrateThread (cap, tso, capabilities[cpu].no); wakeupThreadOnCapability(cap, &capabilities[cpu], tso); } #else diff --git a/rts/Schedule.h b/rts/Schedule.h index 5f669b3..6751144 100644 --- a/rts/Schedule.h +++ b/rts/Schedule.h @@ -139,7 +139,7 @@ appendToRunQueue (Capability *cap, StgTSO *tso) setTSOLink(cap, cap->run_queue_tl, tso); } cap->run_queue_tl = tso; - traceSchedEvent (cap, EVENT_THREAD_RUNNABLE, tso, 0); + traceEventThreadRunnable (cap, tso); } /* Push a thread on the beginning of the run queue. diff --git a/rts/Sparks.c b/rts/Sparks.c index a17b78c..e5e6d7e 100644 --- a/rts/Sparks.c +++ b/rts/Sparks.c @@ -47,7 +47,7 @@ createSparkThread (Capability *cap) tso = createIOThread (cap, RtsFlags.GcFlags.initialStkSize, &base_GHCziConc_runSparks_closure); - traceSchedEvent(cap, EVENT_CREATE_SPARK_THREAD, 0, tso->id); + traceEventCreateSparkThread(cap, tso->id); appendToRunQueue(cap,tso); } diff --git a/rts/Threads.c b/rts/Threads.c index 799cf90..8eaa951 100644 --- a/rts/Threads.c +++ b/rts/Threads.c @@ -107,7 +107,7 @@ createThread(Capability *cap, nat size) RELEASE_LOCK(&sched_mutex); // ToDo: report the stack size in the event? - traceSchedEvent (cap, EVENT_CREATE_THREAD, tso, tso->stack_size); + traceEventCreateThread(cap, tso); return tso; } @@ -254,7 +254,7 @@ unblockOne_ (Capability *cap, StgTSO *tso, cap->context_switch = 1; #endif - traceSchedEvent (cap, EVENT_THREAD_WAKEUP, tso, tso->cap->no); + traceEventThreadWakeup (cap, tso, tso->cap->no); return next; } diff --git a/rts/Trace.c b/rts/Trace.c index 7cfb78c..a1da991 100644 --- a/rts/Trace.c +++ b/rts/Trace.c @@ -9,10 +9,11 @@ // external headers #include "Rts.h" -#ifdef TRACING - // internal headers #include "Trace.h" + +#ifdef TRACING + #include "GetTime.h" #include "Stats.h" #include "eventlog/EventLog.h" @@ -310,6 +311,7 @@ void traceUserMsg(Capability *cap, char *msg) postUserMsg(cap, msg); } } + dtraceUserMsg(cap->no, msg); } void traceThreadStatus_ (StgTSO *tso USED_IF_DEBUG) @@ -345,3 +347,15 @@ void traceEnd (void) #endif /* DEBUG */ #endif /* TRACING */ + +// If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land +// wrapper for the user-msg probe (as we can't expand that in PrimOps.cmm) +// +#if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) + +void dtraceUserMsgWrapper(Capability *cap, char *msg) +{ + dtraceUserMsg(cap->no, msg); +} + +#endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */ diff --git a/rts/Trace.h b/rts/Trace.h index 21828d2..f8b6ad4 100644 --- a/rts/Trace.h +++ b/rts/Trace.h @@ -2,7 +2,7 @@ * * (c) The GHC Team, 2008-2009 * - * Support for fast binary event logging. + * Support for fast binary event logging and user-space dtrace probes. * * ---------------------------------------------------------------------------*/ @@ -12,6 +12,10 @@ #include "rts/EventLogFormat.h" #include "Capability.h" +#if defined(DTRACE) +#include "RtsProbes.h" +#endif /* defined(DTRACE) */ + BEGIN_RTS_PRIVATE // ----------------------------------------------------------------------------- @@ -152,6 +156,237 @@ void traceThreadStatus_ (StgTSO *tso); #endif /* TRACING */ +// If DTRACE is enabled, but neither DEBUG nor TRACING, we need a C land +// wrapper for the user-msg probe (as we can't expand that in PrimOps.cmm) +// +#if !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) + +void dtraceUserMsgWrapper(Capability *cap, char *msg); + +#endif /* !defined(DEBUG) && !defined(TRACING) && defined(DTRACE) */ + +// ----------------------------------------------------------------------------- +// Aliases for static dtrace probes if dtrace is available +// ----------------------------------------------------------------------------- + +#if defined(DTRACE) + +#define dtraceCreateThread(cap, tid) \ + HASKELLEVENT_CREATE_THREAD(cap, tid) +#define dtraceRunThread(cap, tid) \ + HASKELLEVENT_RUN_THREAD(cap, tid) +#define dtraceStopThread(cap, tid, status) \ + HASKELLEVENT_STOP_THREAD(cap, tid, status) +#define dtraceThreadRunnable(cap, tid) \ + HASKELLEVENT_THREAD_RUNNABLE(cap, tid) +#define dtraceMigrateThread(cap, tid, new_cap) \ + HASKELLEVENT_MIGRATE_THREAD(cap, tid, new_cap) +#define dtraceRunSpark(cap, tid) \ + HASKELLEVENT_RUN_SPARK(cap, tid) +#define dtraceStealSpark(cap, tid, victim_cap) \ + HASKELLEVENT_STEAL_SPARK(cap, tid, victim_cap) +#define dtraceShutdown(cap) \ + HASKELLEVENT_SHUTDOWN(cap) +#define dtraceThreadWakeup(cap, tid, other_cap) \ + HASKELLEVENT_THREAD_WAKEUP(cap, tid, other_cap) +#define dtraceGcStart(cap) \ + HASKELLEVENT_GC_START(cap) +#define dtraceGcEnd(cap) \ + HASKELLEVENT_GC_END(cap) +#define dtraceRequestSeqGc(cap) \ + HASKELLEVENT_REQUEST_SEQ_GC(cap) +#define dtraceRequestParGc(cap) \ + HASKELLEVENT_REQUEST_PAR_GC(cap) +#define dtraceCreateSparkThread(cap, spark_tid) \ + HASKELLEVENT_CREATE_SPARK_THREAD(cap, spark_tid) +#define dtraceStartup(num_caps) \ + HASKELLEVENT_STARTUP(num_caps) +#define dtraceUserMsg(cap, msg) \ + HASKELLEVENT_USER_MSG(cap, msg) +#define dtraceGcIdle(cap) \ + HASKELLEVENT_GC_IDLE(cap) +#define dtraceGcWork(cap) \ + HASKELLEVENT_GC_WORK(cap) +#define dtraceGcDone(cap) \ + HASKELLEVENT_GC_DONE(cap) + +#else /* !defined(DTRACE) */ + +#define dtraceCreateThread(cap, tid) /* nothing */ +#define dtraceRunThread(cap, tid) /* nothing */ +#define dtraceStopThread(cap, tid, status) /* nothing */ +#define dtraceThreadRunnable(cap, tid) /* nothing */ +#define dtraceMigrateThread(cap, tid, new_cap) /* nothing */ +#define dtraceRunSpark(cap, tid) /* nothing */ +#define dtraceStealSpark(cap, tid, victim_cap) /* nothing */ +#define dtraceShutdown(cap) /* nothing */ +#define dtraceThreadWakeup(cap, tid, other_cap) /* nothing */ +#define dtraceGcStart(cap) /* nothing */ +#define dtraceGcEnd(cap) /* nothing */ +#define dtraceRequestSeqGc(cap) /* nothing */ +#define dtraceRequestParGc(cap) /* nothing */ +#define dtraceCreateSparkThread(cap, spark_tid) /* nothing */ +#define dtraceStartup(num_caps) /* nothing */ +#define dtraceUserMsg(cap, msg) /* nothing */ +#define dtraceGcIdle(cap) /* nothing */ +#define dtraceGcWork(cap) /* nothing */ +#define dtraceGcDone(cap) /* nothing */ + +#endif + +// ----------------------------------------------------------------------------- +// Trace probes dispatching to various tracing frameworks +// +// In order to avoid accumulating multiple calls to tracing calls at trace +// points, we define inline probe functions that contain the various +// invocations. +// +// Dtrace - dtrace probes are unconditionally added as probe activation is +// handled by the dtrace component of the kernel, and inactive probes are +// very cheap — usually, one no-op. Consequently, dtrace can be used with +// all flavours of the RTS. In addition, we still support logging events to +// a file, even in the presence of dtrace. This is, eg, useful when tracing +// on a server, but browsing trace information with ThreadScope on a local +// client. +// +// ----------------------------------------------------------------------------- + +INLINE_HEADER void traceEventCreateThread(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_CREATE_THREAD, tso, tso->stack_size); + dtraceCreateThread((EventCapNo)cap->no, (EventThreadID)tso->id); +} + +INLINE_HEADER void traceEventRunThread(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_RUN_THREAD, tso, tso->what_next); + dtraceRunThread((EventCapNo)cap->no, (EventThreadID)tso->id); +} + +INLINE_HEADER void traceEventStopThread(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED, + StgThreadReturnCode status STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_STOP_THREAD, tso, status); + dtraceStopThread((EventCapNo)cap->no, (EventThreadID)tso->id, + (EventThreadStatus)status); +} + +// needs to be EXTERN_INLINE as it is used in another EXTERN_INLINE function +EXTERN_INLINE void traceEventThreadRunnable(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED); + +EXTERN_INLINE void traceEventThreadRunnable(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_THREAD_RUNNABLE, tso, 0); + dtraceThreadRunnable((EventCapNo)cap->no, (EventThreadID)tso->id); +} + +INLINE_HEADER void traceEventMigrateThread(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED, + nat new_cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_MIGRATE_THREAD, tso, new_cap); + dtraceMigrateThread((EventCapNo)cap->no, (EventThreadID)tso->id, + (EventCapNo)new_cap); +} + +INLINE_HEADER void traceEventRunSpark(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_RUN_SPARK, tso, 0); + dtraceRunSpark((EventCapNo)cap->no, (EventThreadID)tso->id); +} + +INLINE_HEADER void traceEventStealSpark(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED, + nat victim_cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_STEAL_SPARK, tso, victim_cap); + dtraceStealSpark((EventCapNo)cap->no, (EventThreadID)tso->id, + (EventCapNo)victim_cap); +} + +INLINE_HEADER void traceEventShutdown(Capability *cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_SHUTDOWN, 0, 0); + dtraceShutdown((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventThreadWakeup(Capability *cap STG_UNUSED, + StgTSO *tso STG_UNUSED, + nat other_cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_THREAD_WAKEUP, tso, other_cap); + dtraceThreadWakeup((EventCapNo)cap->no, (EventThreadID)tso->id, + (EventCapNo)other_cap); +} + +INLINE_HEADER void traceEventGcStart(Capability *cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_GC_START, 0, 0); + dtraceGcStart((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventGcEnd(Capability *cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_GC_END, 0, 0); + dtraceGcEnd((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventRequestSeqGc(Capability *cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_REQUEST_SEQ_GC, 0, 0); + dtraceRequestSeqGc((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventRequestParGc(Capability *cap STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_REQUEST_PAR_GC, 0, 0); + dtraceRequestParGc((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventCreateSparkThread(Capability *cap STG_UNUSED, + StgThreadID spark_tid STG_UNUSED) +{ + traceSchedEvent(cap, EVENT_CREATE_SPARK_THREAD, 0, spark_tid); + dtraceCreateSparkThread((EventCapNo)cap->no, (EventThreadID)spark_tid); +} + +// This applies only to dtrace as EVENT_STARTUP in the logging framework is +// handled specially in 'EventLog.c'. +// +INLINE_HEADER void dtraceEventStartup(void) +{ +#ifdef THREADED_RTS + // XXX n_capabilities hasn't been initislised yet + dtraceStartup(RtsFlags.ParFlags.nNodes); +#else + dtraceStartup(1); +#endif +} + +INLINE_HEADER void traceEventGcIdle(Capability *cap STG_UNUSED) +{ + traceEvent(cap, EVENT_GC_IDLE); + dtraceGcIdle((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventGcWork(Capability *cap STG_UNUSED) +{ + traceEvent(cap, EVENT_GC_WORK); + dtraceGcWork((EventCapNo)cap->no); +} + +INLINE_HEADER void traceEventGcDone(Capability *cap STG_UNUSED) +{ + traceEvent(cap, EVENT_GC_DONE); + dtraceGcDone((EventCapNo)cap->no); +} + END_RTS_PRIVATE #endif /* TRACE_H */ diff --git a/rts/eventlog/EventLog.c b/rts/eventlog/EventLog.c index a48c92e..ede1615 100644 --- a/rts/eventlog/EventLog.c +++ b/rts/eventlog/EventLog.c @@ -13,7 +13,6 @@ #include "Trace.h" #include "Capability.h" -#include "Trace.h" #include "RtsUtils.h" #include "Stats.h" #include "EventLog.h" diff --git a/rts/ghc.mk b/rts/ghc.mk index c3d7eb6..bffdaae 100644 --- a/rts/ghc.mk +++ b/rts/ghc.mk @@ -70,6 +70,11 @@ rts/dist/build/sm/Scav_thr.c : rts/sm/Scav.c | $$(dir $$@)/. rts_H_FILES = $(wildcard includes/*.h) $(wildcard rts/*.h) +ifeq "$(HaveDtrace)" "YES" +DTRACEPROBES_H = rts/dist/build/RtsProbes.h +rts_H_FILES += $(DTRACEPROBES_H) +endif + # collect the -l flags that we need to link the rts dyn lib. rts/libs.depend : $(GHC_PKG_INPLACE) "$(GHC_PKG_INPLACE)" field rts extra-libraries \ @@ -362,9 +367,15 @@ rts_dist_C_SRCS = $(rts_C_SRCS) $(rts_thr_EXTRA_C_SRCS) rts_dist_S_SRCS = $(rts_S_SRCS) rts_dist_C_FILES = $(rts_C_SRCS) $(rts_thr_EXTRA_C_SRCS) $(rts_S_SRCS) +ifeq "$(HaveDtrace)" "YES" + +rts_dist_MKDEPENDC_OPTS += -Irts/dist/build + +endif + $(eval $(call build-dependencies,rts,dist)) -$(rts_dist_depfile_c_asm) : libffi/dist-install/build/ffi.h +$(rts_dist_depfile_c_asm) : libffi/dist-install/build/ffi.h $(DTRACEPROBES_H) #----------------------------------------------------------------------------- # libffi stuff @@ -383,6 +394,20 @@ $(DYNWRAPPER_PROG): $(DYNWRAPPER_SRC) "$(HC)" -cpp -optc-include -optcdyn-wrapper-patchable-behaviour.h $(INPLACE_EXTRA_FLAGS) $< -o $@ # ----------------------------------------------------------------------------- +# compile dtrace probes if dtrace is supported + +ifeq "$(HaveDtrace)" "YES" + +rts_CC_OPTS += -DDTRACE +rts_HC_OPTS += -DDTRACE + +DTRACEPROBES_SRC = rts/RtsProbes.d +$(DTRACEPROBES_H): $(DTRACEPROBES_SRC) | $(dir $@)/. + "$(DTRACE)" $(filter -I%,$(rts_CC_OPTS)) -C -h -o $@ -s $< + +endif + +# ----------------------------------------------------------------------------- # build the static lib containing the C main symbol rts/dist/build/libHSrtsmain.a : rts/dist/build/Main.o diff --git a/rts/sm/GC.c b/rts/sm/GC.c index 63023b6..3bd5017 100644 --- a/rts/sm/GC.c +++ b/rts/sm/GC.c @@ -1008,7 +1008,7 @@ scavenge_until_all_done (void) loop: - traceEvent(&capabilities[gct->thread_index], EVENT_GC_WORK); + traceEventGcWork(&capabilities[gct->thread_index]); #if defined(THREADED_RTS) if (n_gc_threads > 1) { @@ -1023,7 +1023,7 @@ loop: // scavenge_loop() only exits when there's no work to do r = dec_running(); - traceEvent(&capabilities[gct->thread_index], EVENT_GC_IDLE); + traceEventGcIdle(&capabilities[gct->thread_index]); debugTrace(DEBUG_gc, "%d GC threads still running", r); @@ -1039,7 +1039,7 @@ loop: // scavenge_loop() to perform any pending work. } - traceEvent(&capabilities[gct->thread_index], EVENT_GC_DONE); + traceEventGcDone(&capabilities[gct->thread_index]); } #if defined(THREADED_RTS) -- 1.7.10.4