summaryrefslogtreecommitdiff
path: root/rts
diff options
context:
space:
mode:
authorEdward Z. Yang <ezyang@mit.edu>2011-07-30 16:02:10 -0400
committerEdward Z. Yang <ezyang@mit.edu>2011-07-30 22:42:16 -0400
commit2088abaf4173090e343b521dc89d622936fba850 (patch)
treeb91cb65036f5231cfc83fcc3e9610922db47e81a /rts
parent2ad66b597b139ea73830f2aedf564df2b72960e9 (diff)
downloadhaskell-2088abaf4173090e343b521dc89d622936fba850.tar.gz
Implement public interface for GC statistics.
We add a new RTS flag -T for collecting statistics but not giving any new inputs. There is one new struct in rts/storage/GC.h: GCStats. We add two new global counters current_residency and current_slop, which are useful for in-program GC statistics. See GHC.Stats in base for a Haskell interface to this functionality. Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
Diffstat (limited to 'rts')
-rw-r--r--rts/Linker.c1
-rw-r--r--rts/RtsFlags.c5
-rw-r--r--rts/Stats.c77
3 files changed, 80 insertions, 3 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index 781f705536..f5b90d41b9 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -793,6 +793,7 @@ typedef struct _RtsSymbolVal {
SymI_HasProto(getOrSetGHCConcWindowsProddingStore) \
SymI_HasProto(getOrSetSystemEventThreadEventManagerStore) \
SymI_HasProto(getOrSetSystemEventThreadIOManagerThreadStore) \
+ SymI_HasProto(getGCStats) \
SymI_HasProto(genSymZh) \
SymI_HasProto(genericRaise) \
SymI_HasProto(getProgArgv) \
diff --git a/rts/RtsFlags.c b/rts/RtsFlags.c
index fcc1f49a36..eda327dd50 100644
--- a/rts/RtsFlags.c
+++ b/rts/RtsFlags.c
@@ -236,6 +236,7 @@ usage_text[] = {
" -I<sec> Perform full GC after <sec> idle time (default: 0.3, 0 == off)",
#endif
"",
+" -T Collect GC statistics (useful for in-program statistics access)"
" -t[<file>] One-line GC statistics (if <file> omitted, uses stderr)",
" -s[<file>] Summary GC statistics (if <file> omitted, uses stderr)",
" -S[<file>] Detailed GC statistics (if <file> omitted, uses stderr)",
@@ -841,6 +842,10 @@ error = rtsTrue;
}
break;
+ case 'T':
+ RtsFlags.GcFlags.giveStats = COLLECT_GC_STATS;
+ break; /* Don't initialize statistics file. */
+
case 'S':
RtsFlags.GcFlags.giveStats = VERBOSE_GC_STATS;
goto stats;
diff --git a/rts/Stats.c b/rts/Stats.c
index c071ec0202..ebe239f06e 100644
--- a/rts/Stats.c
+++ b/rts/Stats.c
@@ -56,9 +56,12 @@ static Ticks HCe_start_time, HCe_tot_time = 0; // heap census prof elap time
#define PROF_VAL(x) 0
#endif
-static lnat max_residency = 0; // in words; for stats only
+// current = current as of last GC
+static lnat current_residency = 0; // in words; for stats only
+static lnat max_residency = 0;
static lnat cumulative_residency = 0;
static lnat residency_samples = 0; // for stats only
+static lnat current_slop = 0;
static lnat max_slop = 0;
static lnat GC_end_faults = 0;
@@ -367,6 +370,7 @@ stat_endGC (gc_thread *gct,
if (live > max_residency) {
max_residency = live;
}
+ current_residency = live;
residency_samples++;
cumulative_residency += live;
}
@@ -510,6 +514,9 @@ StgInt TOTAL_CALLS=1;
statsPrintf(" (SLOW_CALLS_" #arity ") %% of (TOTAL_CALLS) : %.1f%%\n", \
SLOW_CALLS_##arity * 100.0/TOTAL_CALLS)
+static inline Ticks get_init_cpu(void) { return end_init_cpu - start_init_cpu; }
+static inline Ticks get_init_elapsed(void) { return end_init_elapsed - start_init_elapsed; }
+
void
stat_exit(int alloc)
{
@@ -553,8 +560,8 @@ stat_exit(int alloc)
gc_elapsed += GC_coll_elapsed[i];
}
- init_cpu = end_init_cpu - start_init_cpu;
- init_elapsed = end_init_elapsed - start_init_elapsed;
+ init_cpu = get_init_cpu();
+ init_elapsed = get_init_elapsed();
exit_cpu = end_exit_cpu - start_exit_cpu;
exit_elapsed = end_exit_elapsed - start_exit_elapsed;
@@ -844,6 +851,70 @@ statDescribeGens(void)
extern HsInt64 getAllocations( void )
{ return (HsInt64)GC_tot_alloc * sizeof(W_); }
+/* EZY: I'm not convinced I got all the casting right. */
+
+extern void getGCStats( GCStats *s )
+{
+ nat total_collections = 0;
+ nat g;
+ Ticks gc_cpu = 0;
+ Ticks gc_elapsed = 0;
+ Ticks current_elapsed = 0;
+ Ticks current_cpu = 0;
+
+ getProcessTimes(&current_cpu, &current_elapsed);
+
+ /* EZY: static inline'ify these */
+ for (g = 0; g < RtsFlags.GcFlags.generations; g++)
+ total_collections += generations[g].collections;
+
+ for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
+ gc_cpu += GC_coll_cpu[g];
+ gc_elapsed += GC_coll_elapsed[g];
+ }
+
+ s->bytes_allocated = GC_tot_alloc*(StgWord64)sizeof(W_);
+ s->num_gcs = total_collections;
+ s->num_byte_usage_samples = residency_samples;
+ s->max_bytes_used = max_residency*sizeof(W_);
+ s->cumulative_bytes_used = cumulative_residency*(StgWord64)sizeof(W_);
+ s->peak_megabytes_allocated = (StgWord64)(peak_mblocks_allocated * MBLOCK_SIZE / (1024L * 1024L));
+ s->bytes_copied = GC_tot_copied*(StgWord64)sizeof(W_);
+ s->max_bytes_slop = max_slop*(StgWord64)sizeof(W_);
+ s->current_bytes_used = current_residency*(StgWord64)sizeof(W_);
+ s->current_bytes_slop = current_slop*(StgWord64)sizeof(W_);
+ /*
+ s->init_cpu_seconds = TICK_TO_DBL(get_init_cpu());
+ s->init_wall_seconds = TICK_TO_DBL(get_init_elapsed());
+ */
+ s->mutator_cpu_seconds = TICK_TO_DBL(current_cpu - end_init_cpu - gc_cpu - PROF_VAL(RP_tot_time + HC_tot_time));
+ s->mutator_wall_seconds = TICK_TO_DBL(current_elapsed- end_init_elapsed - gc_elapsed);
+ s->gc_cpu_seconds = TICK_TO_DBL(gc_cpu);
+ s->gc_wall_seconds = TICK_TO_DBL(gc_elapsed);
+ s->par_avg_bytes_copied = GC_par_avg_copied*(StgWord64)sizeof(W_);
+ s->par_max_bytes_copied = GC_par_max_copied*(StgWord64)sizeof(W_);
+}
+// extern void getTaskStats( TaskStats **s ) {}
+#if 0
+extern void getSparkStats( SparkCounters *s ) {
+ nat i;
+ s->created = 0;
+ s->dud = 0;
+ s->overflowed = 0;
+ s->converted = 0;
+ s->gcd = 0;
+ s->fizzled = 0;
+ for (i = 0; i < n_capabilities; i++) {
+ s->created += capabilities[i].spark_stats.created;
+ s->dud += capabilities[i].spark_stats.dud;
+ s->overflowed+= capabilities[i].spark_stats.overflowed;
+ s->converted += capabilities[i].spark_stats.converted;
+ s->gcd += capabilities[i].spark_stats.gcd;
+ s->fizzled += capabilities[i].spark_stats.fizzled;
+ }
+}
+#endif
+
/* -----------------------------------------------------------------------------
Dumping stuff in the stats file, or via the debug message interface
-------------------------------------------------------------------------- */