[m-rev.] For post-commit review: ThreadScope updates.

Paul Bone pbone at csse.unimelb.edu.au
Sat Apr 2 16:48:06 AEDT 2011


ThreadScope updates.

Introduce some new threadscope events for profiling the use of futures.

Update mercury's threadscope runtime so that it conforms with changes to
ghc-events (the threadscope event library).

runtime/mercury_threadscope.h:
    Add some new typedefs.

runtime/mercury_threadscope.c:
    Conform to changes in the threadscope eventlog format, in particular which
    event IDs belong to which events.

    Support the capset[3] events created by Duncan Coutts.  Within Mercury we
    refer to capsets as "engine sets".

    Remove our runtime type event and use the capset runtime identifier event
    which takes a string rather than an integer.

    Use #define'd constants rather than magic numbers for the sizes of event
    attributes.

    Make the sparking event a Mercury specific event.  It appears that GHC
    won't use this, even in the future[1, 2].

runtime/mercury_threadscope.h:
runtime/mercury_threadscope.c:
    Add support for new threadscope events:
        New Future - A future is being created, the context of this event tells
                     us which parallel conjunction the future belongs to.
        Wait on Future - Attempt to wait on the production of a future, both
                         with and without suspending the current thread because
                         the future may already be available.
        Signal future - After producing a value for a future signal that that value is now available.

    Note that waking up after suspending on a future is available already via
    THREAD_RUNNABLE when the thread is added to the run queue, and
    THREAD_RUNNING when an engine begins executing that thread.

runtime/mercury_par_builtin.h:
    Use the new threadscope events for instrumenting the use of futures.

References:

  1. There are commented out event ids for creating sparks that are marked as
     deprecated in the ghc-events tool.

  2. Online conversation in #ghc on irc.freenode.net, Simon said that Sparks
     will be deprecated in favor of: https://github.com/simonmar/monad-par.
     Which, I believe, is covered in a paper submitted a paper to ICFP.

  3. http://tinyurl.com/67gf2om

Index: runtime/mercury_par_builtin.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_par_builtin.h,v
retrieving revision 1.2
diff -u -p -b -r1.2 mercury_par_builtin.h
--- runtime/mercury_par_builtin.h	9 Oct 2010 23:43:18 -0000	1.2
+++ runtime/mercury_par_builtin.h	2 Apr 2011 05:34:25 -0000
@@ -85,6 +85,7 @@ vim: ft=c ts=4 sw=4 et
                                                                             \
             Future->MR_fut_signalled = MR_FALSE;                            \
             Future->MR_fut_suspended = NULL;                                \
+            MR_maybe_post_new_future(Future);                               \
         } while (0)
 
     /*
@@ -107,6 +108,7 @@ vim: ft=c ts=4 sw=4 et
             if (Future->MR_fut_signalled) {                                 \
                 Value = Future->MR_fut_value;                               \
                 MR_UNLOCK(&(Future->MR_fut_lock), "future.wait");           \
+                MR_maybe_post_wait_future_nosuspend(Future);                \
             } else {                                                        \
                 MR_Context *ctxt;                                           \
                                                                             \
@@ -131,6 +133,7 @@ vim: ft=c ts=4 sw=4 et
                 Future->MR_fut_suspended = ctxt;                            \
                                                                             \
                 MR_UNLOCK(&(Future->MR_fut_lock), "future.wait");           \
+                MR_maybe_post_wait_future_suspended(Future);                \
                                                                             \
                 MR_maybe_post_stop_context;                                 \
                 MR_ENGINE(MR_eng_this_context) = NULL;                      \
@@ -138,18 +141,6 @@ vim: ft=c ts=4 sw=4 et
             }                                                               \
         } while (0)
 
-#ifdef MR_THREADSCOPE
-    #define MR_maybe_post_stop_context                                      \
-        do {                                                                \
-            MR_threadscope_post_stop_context(MR_TS_STOP_REASON_BLOCKED);    \
-        } while (0)
-
-#else
-    #define MR_maybe_post_stop_context                                      \
-        do {                                                                \
-        } while (0)
-#endif
-
     #define MR_par_builtin_get_future(Future, Value)                        \
         do {                                                                \
             assert(Future->MR_fut_signalled);                               \
@@ -161,6 +152,11 @@ vim: ft=c ts=4 sw=4 et
             MR_Context *ctxt;                                               \
             MR_Context *next;                                               \
                                                                             \
+            /*                                                              \
+            ** Post the threadscope signal future message before waking any \
+            ** threads (and posting those messages.                         \
+            */                                                              \
+            MR_maybe_post_signal_future(Future);                            \
             MR_LOCK(&(Future->MR_fut_lock), "future.signal");               \
                                                                             \
             /*                                                              \
@@ -186,6 +182,43 @@ vim: ft=c ts=4 sw=4 et
             MR_UNLOCK(&(Future->MR_fut_lock), "future.signal");             \
         } while (0)
 
+#ifdef MR_THREADSCOPE
+    #define MR_maybe_post_stop_context                                      \
+        do {                                                                \
+            MR_threadscope_post_stop_context(MR_TS_STOP_REASON_BLOCKED);    \
+        } while (0)
+
+    #define MR_maybe_post_new_future(future)                                \
+        do {                                                                \
+            MR_threadscope_post_new_future(future);                         \
+        } while (0)
+
+    #define MR_maybe_post_wait_future_nosuspend(future)                     \
+        do {                                                                \
+            MR_threadscope_post_wait_future_nosuspend(future);              \
+        } while (0)
+
+    #define MR_maybe_post_wait_future_suspended(future)                     \
+        do {                                                                \
+            MR_threadscope_post_wait_future_suspended(future);              \
+        } while (0)
+
+    #define MR_maybe_post_signal_future(future)                             \
+        do {                                                                \
+            MR_threadscope_post_signal_future(future);                      \
+        } while (0)
+
+#else
+    #define MR_noop                                                         \
+        do {                                                                \
+        } while (0)
+    #define MR_maybe_post_stop_context MR_noop
+    #define MR_maybe_post_new_future(future) MR_noop
+    #define MR_maybe_post_wait_future_nosuspend(future) MR_noop
+    #define MR_maybe_post_wait_future_suspended(future) MR_noop
+    #define MR_maybe_post_signal_future(future) MR_noop
+#endif
+
 #else
 
     #define MR_par_builtin_new_future(Future)                               \
Index: runtime/mercury_threadscope.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_threadscope.c,v
retrieving revision 1.9
diff -u -p -b -r1.9 mercury_threadscope.c
--- runtime/mercury_threadscope.c	25 Mar 2011 03:13:42 -0000	1.9
+++ runtime/mercury_threadscope.c	2 Apr 2011 05:34:25 -0000
@@ -137,33 +137,52 @@ ENDINIT
 #define MR_TS_EVENT_GC_WORK             21 /* () */
 #define MR_TS_EVENT_GC_DONE             22 /* () */
 
+/* 23, 24 used by eden */
+
 /*
-** Duncan Coutts has reserved IDs 23-37 in a discussion via IRC.
+** Capsets or capability sets are groups of engines with some association, for
+** instance a group of threads in a process.
 */
+#define MR_TS_EVENT_CAPSET_CREATE       25 /* (capset, capset_type)  */
+#define MR_TS_EVENT_CAPSET_DELETE       26 /* (capset)               */
+#define MR_TS_EVENT_CAPSET_ASSIGN_CAP   27 /* (capset, cap)          */
+#define MR_TS_EVENT_CAPSET_REMOVE_CAP   28 /* (capset, cap)          */
+/* the RTS identifier is in the form of "GHC-version rts_way"  */
+#define MR_TS_EVENT_RTS_IDENTIFIER      29 /* (capset, name_version_string) */
+/* the vectors in two these events are null separated strings             */
+#define MR_TS_EVENT_PROGRAM_ARGS        30 /* (capset, commandline_vector)  */
+#define MR_TS_EVENT_PROGRAM_ENV         31 /* (capset, environment_vector)  */
 
-#define MR_TS_EVENT_RUNTIME_TYPE        38 /* (rt_type) */
+#define MR_TS_EVENT_OSPROCESS_PID       32 /* (capset, pid, parent_pid)     */
 
+/*
+** Duncan Coutts has reserved IDs 33-37 in a discussion via IRC.
+*/
+#define MR_TS_EVENT_LOOKING_FOR_GLOBAL_WORK \
+                                        38 /* () */
 #define MR_TS_EVENT_STRING              39 /* (string, id) */
 #define MR_TS_EVENT_CALL_MAIN           40 /* () */
-#define MR_TS_EVENT_LOOKING_FOR_GLOBAL_WORK \
-                                        41 /* () */
-                                        /* XXX: Is it possible to infer the
-                                         * dynamic conj id here? */
-#define MR_TS_EVENT_SPARKING            42 /* (int id, spark id) */
 
-#define MR_TS_NUM_EVENT_TAGS            43
+#define MR_TS_NUM_EVENT_TAGS            41
 
 #define MR_TS_MER_EVENT_START           100
 
 #define MR_TS_MER_EVENT_START_PAR_CONJ    100 /* (int id, memo'd string id) */
 #define MR_TS_MER_EVENT_STOP_PAR_CONJ     101 /* (int id) */
-#define MR_TS_MER_EVENT_STOP_PAR_CONJUNCT 102 /* (itn id) */
+#define MR_TS_MER_EVENT_STOP_PAR_CONJUNCT   102 /* (int id) */
+/*
+** Creating sparks is not specifically mercury, but conjunct IDs are,
+** If other systems wish to use this event they can move it to the main events
+** section.
+*/
+#define MR_TS_MER_EVENT_SPARKING            103 /* (int id, spark id) */
 
-#define MR_TS_NUM_MER_EVENTS            3
+#define MR_TS_MER_EVENT_FUT_CREATE          104 /* (fut id) */
+#define MR_TS_MER_EVENT_FUT_WAIT_NOSUSPEND  105 /* (fut id) */
+#define MR_TS_MER_EVENT_FUT_WAIT_SUSPENDED  106 /* (fut id) */
+#define MR_TS_MER_EVENT_FUT_SIGNAL          107 /* (fut id) */
 
-#define MR_TS_RUNTIME_HASKELL           0
-#define MR_TS_RUNTIME_EDEN              1
-#define MR_TS_RUNTIME_MERCURY           2
+#define MR_TS_NUM_MER_EVENTS            8
 
 #if 0  /* DEPRECATED EVENTS: */
 #define EVENT_CREATE_SPARK        13 /* (cap, thread) */
@@ -171,6 +190,13 @@ ENDINIT
 #endif
 
 /*
+ * Engine set type values for EVENT_CAPSET_CREATE
+ */
+#define MR_TS_ENGSET_TYPE_CUSTOM        1  /* reserved for end-user applications */
+#define MR_TS_ENGSET_TYPE_OSPROCESS     2  /* engines belong to the same OS process */
+#define MR_TS_ENGSET_TYPE_CLOCKDOMAIN   3  /* engines share a local clock/time      */
+
+/*
 ** GHC uses 2MB per buffer.  Note that the minimum buffer size is the size of
 ** the largest message plus the size of the block marker message, however it is
 ** _sensible_ for the buffer to be much larger so that we make system calls
@@ -232,6 +258,19 @@ typedef struct {
 
 /***************************************************************************/
 
+#define SZ_CAPSET_ID            4
+#define SZ_CAPSET_TYPE          2
+#define SZ_CONTEXT_ID           4
+#define SZ_CONTEXT_STOP_REASON  2
+#define SZ_DYN_CONJ_ID          8
+#define SZ_ENGINELOG_OFFSET     4
+#define SZ_ENGINE_ID            2
+#define SZ_PID                  4
+#define SZ_SPARK_ID             4
+#define SZ_STATIC_CONJ_ID       4
+#define SZ_TIME                 8
+#define SZ_FUTURE_ID            8
+
 static EventTypeDesc event_type_descs[] = {
     {
         /*
@@ -240,7 +279,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_STARTUP,
         "Startup (num_engines)",
-        2 /* MR_EngineId */
+        SZ_ENGINE_ID
     },
     {
         /*
@@ -259,7 +298,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_BLOCK_MARKER,
         "A block of events generated by a specific engine follows",
-        4 + 8 + 2 /* EnginelogOffset, Time, MR_EngineId */
+        SZ_ENGINELOG_OFFSET + SZ_TIME + SZ_ENGINE_ID
     },
     {
         /*
@@ -267,7 +306,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_CREATE_THREAD,
         "A context is created or re-used",
-        4 /* MR_ContextId */
+        SZ_CONTEXT_ID
     },
     {
         /*
@@ -275,7 +314,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_THREAD_RUNNABLE,
         "The context is being placed on the run queue",
-        4 /* MR_ContextId */
+        SZ_CONTEXT_ID
     },
     {
         /*
@@ -283,7 +322,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_RUN_SPARK,
         "Run a spark from the local stack",
-        4 + 4 /* MR_ContextId + MR_SparkId */
+        SZ_CONTEXT_ID + SZ_SPARK_ID
     },
     {
         /*
@@ -292,7 +331,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_STEAL_SPARK,
         "Run a spark stolen from another engine",
-        4 + 2 + 4 /* MR_ContextId + MR_EngineId  + SparkId */
+        SZ_CONTEXT_ID + SZ_ENGINE_ID + SZ_SPARK_ID
     },
     {
         /*
@@ -301,7 +340,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_RUN_THREAD,
         "Run context",
-        4 /* MR_ContextId */
+        SZ_CONTEXT_ID
     },
     {
         /*
@@ -310,7 +349,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_STOP_THREAD,
         "Context stopped",
-        4 + 2 /* MR_ContextId, MR_ContextStopReason */
+        SZ_CONTEXT_ID + SZ_CONTEXT_STOP_REASON
     },
     {
         /*
@@ -318,7 +357,7 @@ static EventTypeDesc event_type_descs[] 
         */
         MR_TS_EVENT_CREATE_SPARK_THREAD,
         "Create a context for executing a spark",
-        4 /* MR_ContextId */
+        SZ_CONTEXT_ID
     },
     {
         MR_TS_EVENT_LOG_MSG,
@@ -343,15 +382,6 @@ static EventTypeDesc event_type_descs[] 
     },
     {
         /*
-        ** The runtime system writes down which type of runtime system it is.
-        ** ie, Haskell, Eden or Mercury.
-        */
-        MR_TS_EVENT_RUNTIME_TYPE,
-        "The type of the runtime",
-        2
-    },
-    {
-        /*
         ** The runtime system registers a string and an ID for it so that the
         ** ID represents the string in future messages.
         */
@@ -374,9 +404,49 @@ static EventTypeDesc event_type_descs[] 
         0
     },
     {
-        MR_TS_EVENT_SPARKING,
+        MR_TS_EVENT_CAPSET_CREATE,
+        "Create an engine set",
+        SZ_CAPSET_ID + SZ_CAPSET_TYPE
+    },
+    {
+        MR_TS_EVENT_CAPSET_DELETE,
+        "Detete an engine set",
+        SZ_CAPSET_ID
+    },
+    {
+        MR_TS_EVENT_CAPSET_ASSIGN_CAP,
+        "Add an engine to an engine set",
+        SZ_CAPSET_ID + SZ_ENGINE_ID
+    },
+    {
+        MR_TS_EVENT_CAPSET_REMOVE_CAP,
+        "Add an engine to an engine set",
+        SZ_CAPSET_ID + SZ_ENGINE_ID
+    },
+    {
+        MR_TS_EVENT_RTS_IDENTIFIER,
+        "The type of the runtime system for this capset",
+        -1
+    },
+    {
+        MR_TS_EVENT_PROGRAM_ARGS,
+        "The command line arguments of this process",
+        -1
+    },
+    {
+        MR_TS_EVENT_PROGRAM_ENV,
+        "The environment variables this process inherited",
+        -1
+    },
+    {
+        MR_TS_EVENT_OSPROCESS_PID,
+        "The pid and parent pid of this process",
+        2*SZ_PID
+    },
+    {
+        MR_TS_MER_EVENT_SPARKING,
         "A spark is being created",
-        8 + 4 /* Dynamic Conj ID + Spark ID */
+        SZ_DYN_CONJ_ID + SZ_SPARK_ID
         /*
          * Note that the dynamic conj ID is only useful for Mercury. other
          * implementors may want different attributes here.
@@ -385,17 +455,41 @@ static EventTypeDesc event_type_descs[] 
     {
         MR_TS_MER_EVENT_START_PAR_CONJ,
         "Start a parallel conjunction (dyn id, static id)",
-        8 + 4 /* Dynamic Conj ID + Static Conj ID */
+        SZ_DYN_CONJ_ID + SZ_STATIC_CONJ_ID
     },
     {
         MR_TS_MER_EVENT_STOP_PAR_CONJ,
         "Stop a parallel conjunction (dyn id)",
-        8 /* Dynamic Conj ID */
+        SZ_DYN_CONJ_ID
     },
     {
         MR_TS_MER_EVENT_STOP_PAR_CONJUNCT,
         "Stop a parallel conjunct (dyn id)",
-        8 /* Dynamic Conj ID */
+        SZ_DYN_CONJ_ID
+    },
+    {
+        /*
+         * The dynamic conjunction id can be inferred from contact, it is the
+         * next conjunction started after this event.
+         */
+        MR_TS_MER_EVENT_FUT_CREATE,
+        "Create a future (future id)",
+        SZ_FUTURE_ID
+    },
+    {
+        MR_TS_MER_EVENT_FUT_WAIT_NOSUSPEND,
+        "Wait on a future without suspending (no waiting) (future id)",
+        SZ_FUTURE_ID
+    },
+    {
+        MR_TS_MER_EVENT_FUT_WAIT_SUSPENDED,
+        "Wait on a future by suspending this thread (future id)",
+        SZ_FUTURE_ID
+    },
+    {
+        MR_TS_MER_EVENT_FUT_SIGNAL,
+        "Signal a future (future id)",
+        SZ_FUTURE_ID
     },
     {
         /* Mark the end of this array. */
@@ -433,6 +527,21 @@ static struct MR_threadscope_event_buffe
 ** An ID that may be allocated to the next string to be registered.
 */
 static MR_TS_StringId   MR_next_string_id = 0;
+static MR_EngSetId      next_engset_id = 0;
+
+static MR_EngSetId      process_engset_id;
+
+/***************************************************************************/
+
+static MR_EngSetId
+get_next_engset_id(void)
+{
+    /*
+     * This is a seperate function as I may have to add locking or atomic ops
+     * later.
+     */
+    return next_engset_id++;
+}
 
 /***************************************************************************/
 
@@ -635,6 +744,27 @@ MR_STATIC_INLINE void put_spark_id(
     put_be_uint32(buffer, spark_id);
 }
 
+MR_STATIC_INLINE void put_engset_id(
+        struct MR_threadscope_event_buffer *buffer,
+        MR_EngSetId engset_id)
+{
+    put_be_uint32(buffer, engset_id);
+}
+
+MR_STATIC_INLINE void put_engset_type(
+        struct MR_threadscope_event_buffer *buffer,
+        MR_EngSetType type)
+{
+    put_be_uint16(buffer, type);
+}
+
+MR_STATIC_INLINE void put_future_id(
+        struct MR_threadscope_event_buffer *buffer,
+        MR_Future* id)
+{
+    put_be_uint64(buffer, (MR_Word)id);
+}
+
 /***************************************************************************/
 
 static struct MR_threadscope_event_buffer*
@@ -653,9 +783,6 @@ static void
 put_event_type(struct MR_threadscope_event_buffer *buffer,
     EventTypeDesc *event_type);
 
-static MR_TS_StringId
-MR_threadscope_register_string(const char *string);
-
 static MR_bool
 flush_event_buffer(struct MR_threadscope_event_buffer *buffer);
 
@@ -665,6 +792,43 @@ maybe_close_block(struct MR_threadscope_
 static void
 open_block(struct MR_threadscope_event_buffer *buffer, MR_Unsigned eng_id);
 
+/***************************************************************************/
+
+static MR_TS_StringId
+MR_threadscope_register_string(const char *string);
+
+/*
+** These four events are used to create and manage engine sets.  Haskell calls
+** these cap sets.
+**
+** The first two work on the global event buffer and are not thread safe.
+*/
+static void
+MR_threadscope_post_create_engset(MR_EngSetId id, MR_EngSetType type);
+
+static void
+MR_threadscope_post_destroy_engset(MR_EngSetId id);
+
+static void
+MR_threadscope_post_engset_add(struct MR_threadscope_event_buffer *buffer,
+    MR_EngSetId id, MR_EngineId eng);
+
+static void
+MR_threadscope_post_engset_remove(MR_EngSetId id, MR_EngineId eng);
+
+/*
+** Post the name and version of the runtime system to the log file.
+**
+** Note that this is the name of the implementation (mmc), not the name of the
+** language (mercury).
+**
+** The name and version are separated by a '-'.
+*/
+static void
+MR_threadscope_post_runtime_identifier(MR_EngSetId id, const char *ident);
+
+/***************************************************************************/
+
 static void
 start_gc_callback(void);
 static void
@@ -719,10 +883,13 @@ MR_setup_threadscope(void)
     MR_open_output_file_and_write_prelude();
 
     /*
-    ** Put the runtime type event in the buffer.
+    ** Post the initial events to the buffer.
     */
-    put_event_header(&global_buffer, MR_TS_EVENT_RUNTIME_TYPE, 0);
-    put_be_uint16(&global_buffer, MR_TS_RUNTIME_MERCURY);
+    process_engset_id = get_next_engset_id();
+    MR_threadscope_post_create_engset(process_engset_id,
+        MR_TS_ENGSET_TYPE_OSPROCESS);
+    MR_threadscope_post_runtime_identifier(process_engset_id,
+        "mmc-" MR_VERSION);
 
     /*
     ** Put the startup event in the buffer.
@@ -739,6 +906,9 @@ MR_finalize_threadscope(void)
     MR_DO_THREADSCOPE_DEBUG(
         fprintf(stderr, "In finalize threadscope thread: 0x%lx\n", pthread_self())
     );
+
+    MR_threadscope_post_destroy_engset(process_engset_id);
+
     flush_event_buffer(&global_buffer);
     MR_close_output_file();
 }
@@ -760,6 +930,14 @@ MR_threadscope_setup_engine(MercuryEngin
     eng->MR_eng_cpu_clock_ticks_offset = MR_global_offset;
 
     eng->MR_eng_ts_buffer = MR_create_event_buffer();
+
+    MR_threadscope_post_engset_add(eng->MR_eng_ts_buffer, process_engset_id,
+        eng->MR_eng_id);
+    /*
+    ** Flush the buffer to ensure the message above (which lacks a timestamp)
+    ** appears in a sensible place in the buffer.
+    */
+    flush_event_buffer(eng->MR_eng_ts_buffer);
 }
 
 void
@@ -771,6 +949,8 @@ MR_threadscope_finalize_engine(MercuryEn
         fprintf(stderr, "In threadscope finalize engine thread: 0x%lx\n", pthread_self())
     );
 
+    MR_threadscope_post_engset_remove(process_engset_id, eng->MR_eng_id);
+
     MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
 
     if (!enough_room_for_event(buffer, MR_TS_EVENT_SHUTDOWN)) {
@@ -1141,14 +1321,14 @@ MR_threadscope_post_sparking(MR_Word* dy
     struct MR_threadscope_event_buffer *buffer = MR_ENGINE(MR_eng_ts_buffer);
 
     MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
-    if (!enough_room_for_event(buffer, MR_TS_EVENT_SPARKING)) {
+    if (!enough_room_for_event(buffer, MR_TS_MER_EVENT_SPARKING)) {
         flush_event_buffer(buffer);
         open_block(buffer, MR_ENGINE(MR_eng_id));
     } else if (!block_is_open(buffer)) {
         open_block(buffer, MR_ENGINE(MR_eng_id));
     }
 
-    put_event_header(buffer, MR_TS_EVENT_SPARKING,
+    put_event_header(buffer, MR_TS_MER_EVENT_SPARKING,
         get_current_time_nanosecs());
     put_par_conj_dynamic_id(buffer, dynamic_conj_id);
     put_spark_id(buffer, spark_id);
@@ -1310,6 +1490,173 @@ MR_threadscope_post_log_msg(const char *
     MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
 }
 
+void
+MR_threadscope_post_create_engset(MR_EngSetId id, MR_EngSetType type)
+{
+    struct MR_threadscope_event_buffer *buffer = &global_buffer;
+
+    if (!enough_room_for_event(buffer, MR_TS_EVENT_CAPSET_CREATE)) {
+        flush_event_buffer(buffer);
+    }
+
+    put_event_header(buffer, MR_TS_EVENT_CAPSET_CREATE, 0);
+    put_engset_id(buffer, id);
+    put_engset_type(buffer, type);
+}
+
+void
+MR_threadscope_post_destroy_engset(MR_EngSetId id)
+{
+    struct MR_threadscope_event_buffer *buffer = &global_buffer;
+
+    if (!enough_room_for_event(buffer, MR_TS_EVENT_CAPSET_DELETE)) {
+        flush_event_buffer(buffer);
+    }
+
+    put_event_header(buffer, MR_TS_EVENT_CAPSET_DELETE,
+        get_current_time_nanosecs());
+    put_engset_id(buffer, id);
+}
+
+void
+MR_threadscope_post_engset_add(struct MR_threadscope_event_buffer *buffer,
+        MR_EngSetId id, MR_EngineId eng)
+{
+    MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
+    maybe_close_block(buffer);
+    if (!enough_room_for_event(buffer, MR_TS_EVENT_CAPSET_ASSIGN_CAP)) {
+        flush_event_buffer(buffer);
+    }
+
+    /*
+    ** When this event occurs the engine hasn't been setup yet.  Even though we
+    ** use the engine's buffer we cannot use get_current_time_nanosecs()
+    */
+    put_event_header(buffer, MR_TS_EVENT_CAPSET_ASSIGN_CAP, 0);
+    put_engset_id(buffer, id);
+    put_engine_id(buffer, eng);
+
+    MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
+}
+
+void
+MR_threadscope_post_engset_remove(MR_EngSetId id, MR_EngineId eng)
+{
+    struct MR_threadscope_event_buffer *buffer = MR_ENGINE(MR_eng_ts_buffer);
+
+    MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
+    maybe_close_block(buffer);
+    if (!enough_room_for_event(buffer, MR_TS_EVENT_CAPSET_REMOVE_CAP)) {
+        flush_event_buffer(buffer);
+    }
+
+    put_event_header(buffer, MR_TS_EVENT_CAPSET_REMOVE_CAP,
+        get_current_time_nanosecs());
+    put_engset_id(buffer, id);
+    put_engine_id(buffer, eng);
+
+    MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
+}
+
+void
+MR_threadscope_post_runtime_identifier(MR_EngSetId engset_id,
+        const char *identifier)
+{
+    struct MR_threadscope_event_buffer *buffer = &global_buffer;
+    unsigned len;
+
+    len = strlen(identifier);
+
+    if (!enough_room_for_variable_size_event(buffer, len + SZ_CAPSET_ID)) {
+        flush_event_buffer(buffer);
+    }
+
+    put_event_header(buffer, MR_TS_EVENT_RTS_IDENTIFIER, 0);
+    put_be_int16(buffer, len + SZ_CAPSET_ID);
+    put_engset_id(buffer, engset_id);
+    put_raw_string(buffer, identifier, len);
+}
+
+void
+MR_threadscope_post_new_future(MR_Future *future_id)
+{
+    struct MR_threadscope_event_buffer *buffer = MR_ENGINE(MR_eng_ts_buffer);
+
+    MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
+    if (!enough_room_for_event(buffer, MR_TS_MER_EVENT_FUT_CREATE)) {
+        flush_event_buffer(buffer);
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    } else if (!block_is_open(buffer)) {
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    }
+
+    put_event_header(buffer, MR_TS_MER_EVENT_FUT_CREATE,
+        get_current_time_nanosecs());
+    put_future_id(buffer, future_id);
+
+    MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
+}
+
+void
+MR_threadscope_post_wait_future_nosuspend(MR_Future* future_id)
+{
+    struct MR_threadscope_event_buffer *buffer = MR_ENGINE(MR_eng_ts_buffer);
+
+    MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
+    if (!enough_room_for_event(buffer, MR_TS_MER_EVENT_FUT_WAIT_NOSUSPEND)) {
+        flush_event_buffer(buffer);
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    } else if (!block_is_open(buffer)) {
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    }
+
+    put_event_header(buffer, MR_TS_MER_EVENT_FUT_WAIT_NOSUSPEND,
+        get_current_time_nanosecs());
+    put_future_id(buffer, future_id);
+
+    MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
+}
+
+void
+MR_threadscope_post_wait_future_suspended(MR_Future* future_id)
+{
+    struct MR_threadscope_event_buffer *buffer = MR_ENGINE(MR_eng_ts_buffer);
+
+    MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
+    if (!enough_room_for_event(buffer, MR_TS_MER_EVENT_FUT_WAIT_SUSPENDED)) {
+        flush_event_buffer(buffer);
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    } else if (!block_is_open(buffer)) {
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    }
+
+    put_event_header(buffer, MR_TS_MER_EVENT_FUT_WAIT_SUSPENDED,
+        get_current_time_nanosecs());
+    put_future_id(buffer, future_id);
+
+    MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
+}
+
+void
+MR_threadscope_post_signal_future(MR_Future* future_id)
+{
+    struct MR_threadscope_event_buffer *buffer = MR_ENGINE(MR_eng_ts_buffer);
+
+    MR_US_SPIN_LOCK(&(buffer->MR_tsbuffer_lock));
+    if (!enough_room_for_event(buffer, MR_TS_MER_EVENT_FUT_SIGNAL)) {
+        flush_event_buffer(buffer);
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    } else if (!block_is_open(buffer)) {
+        open_block(buffer, MR_ENGINE(MR_eng_id));
+    }
+
+    put_event_header(buffer, MR_TS_MER_EVENT_FUT_SIGNAL,
+        get_current_time_nanosecs());
+    put_future_id(buffer, future_id);
+
+    MR_US_UNLOCK(&(buffer->MR_tsbuffer_lock));
+}
+
 /***************************************************************************/
 
 static struct MR_threadscope_event_buffer*
Index: runtime/mercury_threadscope.h
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_threadscope.h,v
retrieving revision 1.6
diff -u -p -b -r1.6 mercury_threadscope.h
--- runtime/mercury_threadscope.h	25 Mar 2011 03:13:42 -0000	1.6
+++ runtime/mercury_threadscope.h	2 Apr 2011 05:34:25 -0000
@@ -41,6 +41,9 @@ typedef MR_uint_least16_t   MR_ContextSt
 typedef MR_Integer          MR_ContextId;
 typedef MR_uint_least32_t   MR_TS_StringId;
 typedef MR_uint_least32_t   MR_SparkId;
+typedef MR_uint_least32_t   MR_EngSetId;
+typedef MR_uint_least16_t   MR_EngSetType;
+typedef MR_uint_least32_t   MR_TS_Pid;
 
 typedef struct MR_Threadscope_String {
     const char*     MR_tsstring_string;
@@ -179,6 +182,30 @@ extern void
 MR_threadscope_post_stop_par_conjunct(MR_Word* dynamic_id);
 
 /*
+** Post this message when a future is created, this establishes the conjuction
+** id to future id mapping.  The conjunction id is inferred by context.
+*/
+extern void
+MR_threadscope_post_new_future(MR_Future* future_id);
+
+/*
+** Post either of these messages when waiting on a future.  THe first if the
+** context had to be suspended because the future was not available, and the
+** second when the context did not need to be suspended.
+*/
+extern void
+MR_threadscope_post_wait_future_nosuspend(MR_Future* future_id);
+
+extern void
+MR_threadscope_post_wait_future_suspended(MR_Future* future_id);
+
+/*
+** Post this event when signaling the production of a future.
+*/
+extern void
+MR_threadscope_post_signal_future(MR_Future* future_id);
+
+/*
 ** Register all the strings in an array and save their IDs in the array.
 */
 extern void
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 489 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20110402/6d600b9c/attachment.sig>


More information about the reviews mailing list