summaryrefslogtreecommitdiff
path: root/rts/Stats.c
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/Stats.c
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/Stats.c')
-rw-r--r--rts/Stats.c77
1 files changed, 74 insertions, 3 deletions
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
-------------------------------------------------------------------------- */