[m-rev.] diff: Use gettimeofday() for Mercury's ThreadScope support.

Paul Bone pbone at csse.unimelb.edu.au
Wed Jun 20 23:22:11 AEST 2012


On some systems the CPU's time stamp counter (TSC) cannot reliabily be
used.  Mercury's ThreadScope support will now use gettimeofday() by
default, but use of the TSC may be enabled.

Note that in Linux, gettimeofday() does not always make a system call.

runtime/mercury_threadscope.[ch]:
    Add support for measuring time with gettimeofday().

    Use gettimeofday() to measure time by default.

runtime/mercury_atomic_ops.[ch]
    Add a new function MR_tsc_is_sensible(), It returns true if the TSC can
    (as far as the RTS can detect) be used.

    Fix trailing whitespace.

runtime/mercury_wrapper.c:
    Add a new runtime option --threadscope-use-tsc.
    When specified this option allows threadscope to use the CPU's TSC to
    measure time.

doc/userguide.texi:
    Document the --threadscope-use-tsc option.  This documentation is
    commented out.

Index: doc/user_guide.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/user_guide.texi,v
retrieving revision 1.652
diff -u -r1.652 user_guide.texi
--- doc/user_guide.texi	8 Jun 2012 15:37:05 -0000	1.652
+++ doc/user_guide.texi	20 Jun 2012 12:59:10 -0000
@@ -10257,6 +10257,14 @@
 @c information to a file named @file{parallel_execution_profile.txt}.
 @c This only has an effect if the executable was built in a low level c,
 @c parallel, threadscope grade.
+ at c
+ at c @sp 1
+ at c @item --threadscope-use-tsc
+ at c @findex --threadscope-use-tsc
+ at c Requests that the runtime's threadscope support use the CPU's time stamp
+ at c counter (TSC) to measure time rather than gettimeofday().  The TSC may
+ at c not always be available so the runtime may still use gettomeofday() even
+ at c with this option.
 
 @sp 1
 @item --thread-pinning
Index: runtime/mercury_atomic_ops.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_atomic_ops.c,v
retrieving revision 1.13
diff -u -r1.13 mercury_atomic_ops.c
--- runtime/mercury_atomic_ops.c	1 Aug 2011 07:06:20 -0000	1.13
+++ runtime/mercury_atomic_ops.c	20 Jun 2012 12:59:34 -0000
@@ -43,7 +43,7 @@
 )
 
 MR_OUTLINE_DEFN(
-    MR_Integer 
+    MR_Integer
     MR_atomic_add_and_fetch_int(volatile MR_Integer *addr, MR_Integer addend)
 ,
     {
@@ -52,7 +52,7 @@
 )
 
 MR_OUTLINE_DEFN(
-    MR_Unsigned 
+    MR_Unsigned
     MR_atomic_add_and_fetch_uint(volatile MR_Unsigned *addr, MR_Unsigned addend)
 ,
     {
@@ -88,7 +88,7 @@
 )
 
 MR_OUTLINE_DEFN(
-    void 
+    void
     MR_atomic_inc_int(volatile MR_Integer *addr)
 ,
     {
@@ -97,7 +97,7 @@
 )
 
 MR_OUTLINE_DEFN(
-    void 
+    void
     MR_atomic_inc_uint(volatile MR_Unsigned *addr)
 ,
     {
@@ -106,7 +106,7 @@
 )
 
 MR_OUTLINE_DEFN(
-    void 
+    void
     MR_atomic_dec_int(volatile MR_Integer *addr)
 ,
     {
@@ -155,7 +155,7 @@
 #if defined(MR_GNUC) && (defined(__i386__) || defined(__x86_64__))
 
 /* Set this to 1 to enable some printfs below */
-#define MR_DEBUG_CPU_FEATURE_DETECTION 0 
+#define MR_DEBUG_CPU_FEATURE_DETECTION 0
 
 /*
 ** cpuid, rdtscp and rdtsc are i386/x86_64 instructions.
@@ -189,7 +189,7 @@
     MR_Unsigned     extended_family, basic_family, family;
     MR_Unsigned     extended_model, model;
 
-    /* 
+    /*
     ** Check for the CPUID instruction.  CPUID is supported if we can flip bit
     ** 21 in the CPU's EFLAGS register.  The assembly below is written in a
     ** subset of i386 and x86_64 assembly.  To read and write EFLAGS we have
@@ -227,7 +227,7 @@
 
     /* CPUID 1 gives type, family, model and stepping information in EAX. */
     MR_cpuid(1, 0, &a, &b, &c, &d);
-    
+
     /* Bit 4 in EDX is high if RDTSC is available */
     if (d & (1 << 4)) {
         MR_rdtsc_is_available = MR_TRUE;
@@ -268,7 +268,7 @@
     } else {
         family = basic_family;
     }
-    /* 
+    /*
     ** I'm not using the model value but I'll leave the code here incase we
     ** have a reason to use it in the future.
     */
@@ -281,7 +281,7 @@
     }
 #if MR_DEBUG_CPU_FEATURE_DETECTION
     fprintf(stderr, "This is family %d and model %d\n", family, model);
-#endif 
+#endif
 
     /* Now check for P3 or higher since they have the extended pages */
     if (family < 6) {
@@ -297,12 +297,12 @@
 
     /*
     ** Extended CPUID 0x80000000.
-    ** 
+    **
     ** EAX contains the maximum extended CPUID node.
     */
     MR_cpuid(0x80000000, 0, &a, &b, &c, &d);
     if ((a & 0x80000000) == 0) {
-        /* 
+        /*
         ** Extended CPUID is not supported.
         ** Note that this check is still not as reliable as I'd like.  If it
         ** succeeds I'm not confident that the processor definitely implements
@@ -343,7 +343,7 @@
         ** for the cost of a single byte I feel safer using our own.
         */
 #define CPUID_BRAND_STRING_SIZE (3*4*4 + 1)
-        char buff[CPUID_BRAND_STRING_SIZE]; 
+        char buff[CPUID_BRAND_STRING_SIZE];
         unsigned int page;
         unsigned int byte;
         unsigned int shift;
@@ -396,10 +396,10 @@
     unsigned int brand_string_len;
     unsigned int i;
     double       multiplier;
-    int          freq_index = -1; 
+    int          freq_index = -1;
 
     brand_string_len = strlen(string);
-    
+
     /*
     ** There will be at least five characters if we can parse this, three
     ** for the '?Hz' suffix, at least one for the units, plus a space at
@@ -421,7 +421,7 @@
             multiplier = 1000000000.0;
             break;
         case 'T':
-            /* 
+            /*
             ** Yes, this is defined in the specification, Intel have some
             ** strong ambitions regarding Moore's law. :-)  We include it here to
             ** conform with the standard.
@@ -443,7 +443,7 @@
         /* We didn't find the beginning of the frequency */
         return 0;
     }
-   
+
     /*
     ** If strtod fails it returns zero, so if we fail to parse a number here,
     ** we'll return zero which our caller understands as a parsing failure.
@@ -516,6 +516,20 @@
 #endif /* not MR_GNUC && (__i386__ || __x86_64__) */
 }
 
+/*
+** The TSC works and MR_cpu_cycles_per_sec is nonzero.
+*/
+extern MR_bool
+MR_tsc_is_sensible(void)
+{
+#if defined(MR_GNUC) && (defined(__i386__) || defined(__x86_64__))
+    return ((MR_rdtscp_is_available || MR_rdtsc_is_available) &&
+            (MR_cpu_cycles_per_sec != 0));
+#else
+    return MR_FALSE;
+#endif
+}
+
 MR_uint_least64_t
 MR_read_cpu_tsc(void)
 {
@@ -538,7 +552,7 @@
 */
 #if defined(MR_GNUC) && (defined(__i386__) || defined(__x86_64__))
 
-static __inline__ void 
+static __inline__ void
 MR_cpuid(MR_Unsigned code, MR_Unsigned sub_code,
         MR_Unsigned *a, MR_Unsigned *b, MR_Unsigned *c, MR_Unsigned *d)
 {
Index: runtime/mercury_atomic_ops.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_atomic_ops.h,v
retrieving revision 1.23
diff -u -r1.23 mercury_atomic_ops.h
--- runtime/mercury_atomic_ops.h	12 Sep 2011 08:09:24 -0000	1.23
+++ runtime/mercury_atomic_ops.h	20 Jun 2012 12:59:34 -0000
@@ -763,6 +763,12 @@
 MR_profiling_stop_timer(MR_Timer *timer, MR_Stats *stats);
 
 /*
+** The TSC works and MR_cpu_cycles_per_sec is nonzero.
+*/
+extern MR_bool
+MR_tsc_is_sensible(void);
+
+/*
 ** Read the CPU's TSC.  This is currently only implemented for i386 and x86-64
 ** systems.  It returns 0 when support is not available.
 */
Index: runtime/mercury_threadscope.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_threadscope.c,v
retrieving revision 1.20
diff -u -r1.20 mercury_threadscope.c
--- runtime/mercury_threadscope.c	19 Jun 2012 11:08:16 -0000	1.20
+++ runtime/mercury_threadscope.c	20 Jun 2012 12:59:41 -0000
@@ -681,6 +681,12 @@
 static struct MR_threadscope_event_buffer global_buffer;
 
 /*
+** Alternativly we use gettimeofday for measuring time.
+*/
+MR_bool                 MR_threadscope_use_tsc = MR_FALSE;
+static Timedelta        MR_gettimeofday_offset;
+
+/*
 ** An ID that may be allocated to the next string to be registered.
 */
 static MR_TS_StringId   MR_next_string_id = 0;
@@ -968,7 +974,8 @@
 
 /***************************************************************************/
 
-static MR_uint_least64_t get_current_time_nanosecs(void);
+static Time get_current_time_nanosecs(void);
+static Time gettimeofday_nsecs(void);
 
 /***************************************************************************/
 
@@ -978,19 +985,29 @@
     MR_DO_THREADSCOPE_DEBUG(
         fprintf(stderr, "In setup threadscope thread: 0x%lx\n", pthread_self())
     );
-    /* This value is used later when setting up the primordial engine. */
-    MR_primordial_first_tsc = MR_read_cpu_tsc();
 
-    /*
-    ** These variables are used for TSC synchronization which is not used.
-    ** See below.
-    **
-    pthread_mutex_init(&MR_tsc_sync_slave_lock, MR_MUTEX_ATTR);
-    MR_US_COND_CLEAR(&MR_tsc_sync_slave_entry_cond);
-    MR_US_COND_CLEAR(&MR_tsc_sync_master_entry_cond);
-    MR_US_COND_CLEAR(&MR_tsc_sync_t0);
-    MR_US_COND_CLEAR(&MR_tsc_sync_t1);
-    */
+    if (!MR_tsc_is_sensible()) {
+        MR_threadscope_use_tsc = MR_FALSE;
+    }
+
+    if (MR_threadscope_use_tsc) {
+        /* This value is used later when setting up the primordial engine. */
+        MR_primordial_first_tsc = MR_read_cpu_tsc();
+
+        /*
+        ** These variables are used for TSC synchronization which is not used.
+        ** See below.
+        **
+        pthread_mutex_init(&MR_tsc_sync_slave_lock, MR_MUTEX_ATTR);
+        MR_US_COND_CLEAR(&MR_tsc_sync_slave_entry_cond);
+        MR_US_COND_CLEAR(&MR_tsc_sync_master_entry_cond);
+        MR_US_COND_CLEAR(&MR_tsc_sync_t0);
+        MR_US_COND_CLEAR(&MR_tsc_sync_t1);
+        */
+
+    } else {
+        MR_gettimeofday_offset = -1 * gettimeofday_nsecs();
+    }
 
     /* Configure Boehm */
 #ifdef MR_BOEHM_GC
@@ -1047,10 +1064,12 @@
     );
     eng->MR_eng_next_spark_id = 0;
 
-    if (eng->MR_eng_id == 0) {
-        MR_global_offset = -MR_primordial_first_tsc;
+    if (MR_threadscope_use_tsc) {
+        if (eng->MR_eng_id == 0) {
+            MR_global_offset = -MR_primordial_first_tsc;
+        }
+        eng->MR_eng_cpu_clock_ticks_offset = MR_global_offset;
     }
-    eng->MR_eng_cpu_clock_ticks_offset = MR_global_offset;
 
     eng->MR_eng_ts_buffer = MR_create_event_buffer();
 
@@ -2211,21 +2230,38 @@
 
 /***************************************************************************/
 
-static MR_uint_least64_t
+static Time
 get_current_time_nanosecs(void)
 {
-    MR_uint_least64_t   current_tsc;
-    MercuryEngine       *eng = MR_thread_engine_base;
+    if (MR_threadscope_use_tsc) {
+        MR_uint_least64_t   current_tsc;
+        MercuryEngine       *eng = MR_thread_engine_base;
 
-    current_tsc = MR_read_cpu_tsc();
+        current_tsc = MR_read_cpu_tsc();
 
-    if (MR_cpu_cycles_per_sec == 0) {
-        return current_tsc + eng->MR_eng_cpu_clock_ticks_offset;
-    } else {
         /* The large constant (10^9) here converts seconds into nanoseconds. */
         return (current_tsc + eng->MR_eng_cpu_clock_ticks_offset) /
             (MR_cpu_cycles_per_sec / 1000000000);
+    } else {
+        return gettimeofday_nsecs() + MR_gettimeofday_offset;
+    }
+}
+
+static Time
+gettimeofday_nsecs(void)
+{
+    struct timeval      tv;
+
+    if (0 != gettimeofday(&tv, NULL)) {
+        perror("gettimeofday()");
+        /*
+        ** Return a stupid value generating an obviously bad logfile
+        ** rather than crashing a program that may otherwise work.
+        */
+        return 0;
     }
+    return (Time)tv.tv_sec * 1000000000 +
+            (Time)tv.tv_usec * 1000;
 }
 
 /***************************************************************************/
Index: runtime/mercury_threadscope.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_threadscope.h,v
retrieving revision 1.15
diff -u -r1.15 mercury_threadscope.h
--- runtime/mercury_threadscope.h	19 Jun 2012 11:08:16 -0000	1.15
+++ runtime/mercury_threadscope.h	20 Jun 2012 12:59:41 -0000
@@ -50,6 +50,14 @@
 } MR_Threadscope_String;
 
 /*
+** Set this to true to use the CPU's time stamp counter.
+**
+** This is initially set in mercury_wrapper.c and may be reset by
+** MR_setup_threadscope if the TSC can't be used.
+*/
+extern MR_bool MR_threadscope_use_tsc;
+
+/*
 ** This must be called by the primordial thread before starting any other
 ** threads but after the primordial thread has been pinned.
 */
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.229
diff -u -r1.229 mercury_wrapper.c
--- runtime/mercury_wrapper.c	11 Jun 2012 03:02:17 -0000	1.229
+++ runtime/mercury_wrapper.c	20 Jun 2012 12:59:43 -0000
@@ -1313,6 +1313,7 @@
     MR_WORKSTEAL_SLEEP_MSECS,
     MR_THREAD_PINNING,
     MR_PROFILE_PARALLEL_EXECUTION,
+    MR_THREADSCOPE_USE_TSC,
     MR_MDB_TTY,
     MR_MDB_IN,
     MR_MDB_OUT,
@@ -1414,6 +1415,7 @@
         MR_RUNTIME_GRANULAITY_WSDEQUE_LENGTH_FACTOR },
     { "thread-pinning",                 0, 0, MR_THREAD_PINNING },
     { "profile-parallel-execution",     0, 0, MR_PROFILE_PARALLEL_EXECUTION },
+    { "threadscope-use-tsc",            0, 0, MR_THREADSCOPE_USE_TSC },
     { "mdb-tty",                        1, 0, MR_MDB_TTY },
     { "mdb-in",                         1, 0, MR_MDB_IN },
     { "mdb-out",                        1, 0, MR_MDB_OUT },
@@ -1866,6 +1868,12 @@
 #endif
                 break;
 
+            case MR_THREADSCOPE_USE_TSC:
+#ifdef MR_THREAD_SAFE
+                MR_threadscope_use_tsc = MR_TRUE;
+#endif
+                break;
+
             case 'i':
             case MR_MDB_IN:
                 MR_mdb_in_filename = MR_copy_string(MR_optarg);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: Digital signature
URL: <http://lists.mercurylang.org/archives/reviews/attachments/20120620/9d04303a/attachment.sig>


More information about the reviews mailing list