[MLton-devel] Solaris port

Stephen Weeks MLton@mlton.org
Thu, 5 Jun 2003 12:58:10 -0700



> I am not sure it will work as getpid() is used by the libc function 
> getrusage(). And getpid() is itself a system call, hence trick to 
> redefine in C.

Good point.  Caching is also difficult for the reasons Henry
mentioned.

After a little more thought, it wasn't too difficult to prevent
getrusage from being called in all cases unless the timing info is
needed.  A similar trick works to eliminate GC calls to sigprocmask,
which was also high on your list, unless of course the program
actually uses signals.

Here's the relevant diff.

% cvs diff -r 1.137 -r 1.139 gc.c
Index: gc.c
===================================================================
RCS file: /cvsroot/mlton/mlton/runtime/gc.c,v
retrieving revision 1.137
retrieving revision 1.139
diff -u -r1.137 -r1.139
--- gc.c	3 Jun 2003 01:03:26 -0000	1.137
+++ gc.c	5 Jun 2003 19:53:59 -0000	1.139
@@ -1191,12 +1191,24 @@
 }
 #endif /* #if ASSERT */
 
+/* The purpose of blocking signals in GC is to prevent GC_handler from running,
+ * which would muck with s->limit.  However, if the program doesn't handle 
+ * signals, we don't need to block them.  This can be tested via the weak symbol
+ * Posix_Signal_handle.
+ */
+void Posix_Signal_handle () __attribute__ ((weak)); 
+static inline bool shouldBlockSignals () {
+	return 0 != Posix_Signal_handle;
+}
+
 static inline void blockSignals (GC_state s) {
-	sigprocmask (SIG_BLOCK, &s->signalsHandled, NULL);
+	if (shouldBlockSignals ())
+		sigprocmask (SIG_BLOCK, &s->signalsHandled, NULL);
 }
 
 static inline void unblockSignals (GC_state s) {
-	sigprocmask (SIG_UNBLOCK, &s->signalsHandled, NULL);
+	if (shouldBlockSignals ())
+		sigprocmask (SIG_UNBLOCK, &s->signalsHandled, NULL);
 }
 
 /* ---------------------------------------------------------------- */
@@ -1698,12 +1710,17 @@
 	setCardMapForMutator (s);
 }
 
+static inline bool detailedGCTime (GC_state s) {
+	return s->summary;
+}
+
 static void cheneyCopy (GC_state s) {
 	struct rusage ru_start;
 	pointer toStart;
 
 	assert (s->heap2.size >= s->oldGenSize);
-	startTiming (&ru_start);
+	if (detailedGCTime (s))
+		startTiming (&ru_start);
 	s->numCopyingGCs++;
 	s->toSpace = s->heap2.start;
 	s->toLimit = s->heap2.start + s->heap2.size;
@@ -1734,7 +1751,8 @@
 				uintToCommaString (s->oldGenSize));
 	swapSemis (s);
 	clearCrossMap (s);
-	stopTiming (&ru_start, &s->ru_gcCopy);		
+	if (detailedGCTime (s))
+		stopTiming (&ru_start, &s->ru_gcCopy);		
  	if (DEBUG or s->messages)
 		fprintf (stderr, "Major copying GC done.\n");
 }
@@ -1976,7 +1994,8 @@
 	} else {
 		if (DEBUG_GENERATIONAL or s->messages)
 			fprintf (stderr, "Minor GC.\n");
-		startTiming (&ru_start);
+		if (detailedGCTime (s))
+			startTiming (&ru_start);
 		s->amInMinorGC = TRUE;
 		s->toSpace = s->heap.start + s->oldGenSize;
 		if (DEBUG_GENERATIONAL)
@@ -2000,7 +2019,8 @@
 		s->bytesCopiedMinor += bytesCopied;
 		s->oldGenSize += bytesCopied;
 		s->amInMinorGC = FALSE;
-		stopTiming (&ru_start, &s->ru_gcMinor);
+		if (detailedGCTime (s))
+			stopTiming (&ru_start, &s->ru_gcMinor);
 		if (DEBUG_GENERATIONAL or s->messages)
 			fprintf (stderr, "Minor GC done.  %s bytes copied.\n",
 					uintToCommaString (bytesCopied));
@@ -2515,7 +2535,8 @@
 
 	if (DEBUG or s->messages)
 		fprintf (stderr, "Major mark-compact GC.\n");
-	startTiming (&ru_start);		
+	if (detailedGCTime (s))
+		startTiming (&ru_start);		
 	s->numMarkCompactGCs++;
 	foreachGlobal (s, markGlobal);
 	foreachGlobal (s, threadInternal);
@@ -2523,7 +2544,8 @@
 	updateBackwardPointersAndSlide (s);
 	clearCrossMap (s);
 	s->bytesMarkCompacted += s->oldGenSize;
-	stopTiming (&ru_start, &s->ru_gcMarkCompact);
+	if (detailedGCTime (s))
+		stopTiming (&ru_start, &s->ru_gcMarkCompact);
 	if (DEBUG or s->messages)
 		fprintf (stderr, "Major mark-compact GC done.\n");
 }
@@ -2826,6 +2848,18 @@
 	}
 }
 
+/* MLton_Rusage_ru is the only code outside of gc.c that uses gcState.ru_gc.
+ * So, we only need to keep gcTime if gc.c needs it due to s->summary or 
+ * s->messages, or if MLton_Rusage_ru is called.  Because MLton_Rusage_ru is
+ * defined in a file all to itself (basis/MLton/rusage.c), it is called iff it
+ * is linked in, which we can test via a weak symbol.
+ */
+void MLton_Rusage_ru () __attribute__ ((weak));
+static inline bool needGCTime (GC_state s) {
+	return DEBUG or s->summary or s->messages
+		or (0 != MLton_Rusage_ru != 0);
+}
+
 static void doGC (GC_state s, 
 			W32 oldGenBytesRequested,
 			W32 nurseryBytesRequested, 
@@ -2843,7 +2877,8 @@
 				uintToCommaString (nurseryBytesRequested),
 				uintToCommaString (oldGenBytesRequested));
 	assert (invariant (s));
-	startTiming (&ru_start);
+	if (needGCTime (s))
+		startTiming (&ru_start);
 	minorGC (s);
 	stackTopOk = stackTopIsOk (s, s->currentThread->stack);
 	stackBytesRequested =
@@ -2864,8 +2899,11 @@
 	unless (stackTopOk)
 		growStack (s);
 	setStack (s);
-	gcTime = stopTiming (&ru_start, &s->ru_gc);
-	s->maxPause = max (s->maxPause, gcTime);
+	if (needGCTime (s)) {
+		gcTime = stopTiming (&ru_start, &s->ru_gc);
+		s->maxPause = max (s->maxPause, gcTime);
+	} else
+		gcTime = 0;  /* Assign gcTime to quell gcc warning. */
 	if (DEBUG or s->messages) {
 		fprintf (stderr, "Finished gc.\n");
 		fprintf (stderr, "time: %s ms\n", intToCommaString (gcTime));



-------------------------------------------------------
This SF.net email is sponsored by:  Etnus, makers of TotalView, The best
thread debugger on the planet. Designed with thread debugging features
you've never dreamed of, try TotalView 6 free at www.etnus.com.
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel