[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