on master help sign in
A bit more detailed rts stats.
commit6f8ee968e10f3d06c58dca0caf501ed628ec63d7 authorSam T <sta.cs.vsu@gmail.com> dateFri 15 Mar 2013, 21:01 (14 years ago) parent13a7afa
8 files changed+171−31
rts/Makefile+3−2 rts/idris_gc.c+5−8 rts/idris_heap.h+1−2 rts/idris_main.c+11−2 rts/idris_rts.c+21−13 rts/idris_rts.h+4−4 rts/idris_stats.c+53 rts/idris_stats.h+73
rts/Makefile+3−2
@@ -1,8 +1,9 @@
11include ../config.mk
22
3−OBJS = idris_rts.o idris_heap.o idris_gc.o idris_gmp.o idris_stdfgn.o idris_bitstring.o idris_opts.o
4−HDRS = idris_rts.h idris_heap.h idris_gc.h idris_gmp.h idris_stdfgn.h idris_bitstring.h idris_opts.h
3+OBJS = idris_rts.o idris_heap.o idris_gc.o idris_gmp.o idris_stdfgn.o idris_bitstring.o idris_opts.o idris_stats.o
4+HDRS = idris_rts.h idris_heap.h idris_gc.h idris_gmp.h idris_stdfgn.h idris_bitstring.h idris_opts.h idris_stats.h
55CFLAGS = -O2 -Wall
6+
67ifneq ($(GMP_INCLUDE_DIR),)
78 CFLAGS += -isystem $(GMP_INCLUDE_DIR)
89endif
rts/idris_gc.c+5−8
@@ -81,6 +81,7 @@ void cheney(VM *vm) {
8181
8282void idris_gc(VM* vm) {
8383 HEAP_CHECK(vm)
84+ STATS_ENTER_GC(vm->stats, vm->heap.size)
8485 // printf("Collecting\n");
8586
8687 char* newheap = malloc(vm->heap.size);
@@ -92,8 +93,6 @@ void idris_gc(VM* vm) {
9293 vm->heap.next = newheap;
9394 vm->heap.end = newheap + vm->heap.size;
9495
95− vm->collections++;
96−
9796 VAL* root;
9897
9998 for(root = vm->valstack; root < vm->valstack_top; ++root) {
@@ -118,16 +117,14 @@ void idris_gc(VM* vm) {
118117 }
119118 vm->heap.old = oldheap;
120119
121− // gcInfo(vm, 0);
120+ STATS_LEAVE_GC(vm->stats, vm->heap.size, vm->heap.next - vm->heap.heap)
122121 HEAP_CHECK(vm)
123122}
124123
125124void idris_gcInfo(VM* vm, int doGC) {
126− printf("\nStack: %p %p\n", vm->valstack, vm->valstack_top);
127− printf("Total allocations: %d\n", vm->allocations);
128− printf("GCs: %d\n", vm->collections);
129− printf("Final heap size %d\n", (int)(vm->heap.size));
130− printf("Final heap use %d\n", (int)(vm->heap.next - vm->heap.heap));
125+ printf("Stack: <BOT %p> <TOP %p>\n", vm->valstack, vm->valstack_top);
126+ printf("Final heap size %d\n", (int)(vm->heap.size));
127+ printf("Final heap use %d\n", (int)(vm->heap.next - vm->heap.heap));
131128 if (doGC) { idris_gc(vm); }
132129 printf("Final heap use after GC %d\n", (int)(vm->heap.next - vm->heap.heap));
133130}
rts/idris_heap.h+1−2
@@ -8,10 +8,9 @@ typedef struct {
88 char* heap; // Point to bottom of heap
99 char* end; // Point to top of heap
1010 size_t size; // Size of _next_ heap. Size of current heap is /end - heap/.
11− size_t growth; // Quantity of heap growth in bytes. TODO: should it be constant?
11+ size_t growth; // Quantity of heap growth in bytes.
1212
1313 char* old;
14− // TODO heap usage
1514} Heap;
1615
1716
rts/idris_main.c+11−2
@@ -1,5 +1,6 @@
11#include "idris_opts.h"
2−
2+#include "idris_stats.h"
3+#include "idris_rts.h"
34// The default options should give satisfactory results under many circumstances.
45RTSOpts opts = {
56 .init_heap_size = 4096000,
@@ -13,9 +14,17 @@ int main(int argc, char* argv[]) {
1314 VM* vm = init_vm(opts.max_stack_size, opts.init_heap_size, 1, argc, argv);
1415 _idris__123_runMain0_125_(vm, NULL);
1516
17+#ifdef IDRIS_DEBUG
1618 if (opts.show_summary) {
1719 idris_gcInfo(vm, 1);
1820 }
21+#endif
22+
23+ Stats stats = terminate(vm);
24+
25+ if (opts.show_summary) {
26+ print_stats(&stats);
27+ }
1928
20− terminate(vm);
29+ return EXIT_SUCCESS;
2130}
rts/idris_rts.c+21−13
@@ -14,11 +14,15 @@
1414VM* init_vm(int stack_size, size_t heap_size,
1515 int max_threads, // not implemented yet
1616 int argc, char* argv[]) {
17− VAL* valstack = malloc(stack_size*sizeof(VAL));
18− int* intstack = malloc(stack_size*sizeof(int));
19− double* floatstack = malloc(stack_size*sizeof(double));
2017
2118 VM* vm = malloc(sizeof(VM));
19+ STATS_INIT_STATS(vm->stats)
20+ STATS_ENTER_INIT(vm->stats)
21+
22+ VAL* valstack = malloc(stack_size * sizeof(VAL));
23+ int* intstack = malloc(stack_size * sizeof(int));
24+ double* floatstack = malloc(stack_size*sizeof(double));
25+
2226 vm->valstack = valstack;
2327 vm->valstack_top = valstack;
2428 vm->valstack_base = valstack;
@@ -30,9 +34,6 @@ VM* init_vm(int stack_size, size_t heap_size,
3034
3135 alloc_heap(&(vm->heap), heap_size);
3236
33− vm->collections = 0;
34− vm->allocations = 0;
35−
3637 vm->ret = NULL;
3738 vm->reg1 = NULL;
3839
@@ -59,23 +60,28 @@ VM* init_vm(int stack_size, size_t heap_size,
5960 vm->argv[i] = MKSTR(vm, argv[i]);
6061 }
6162
63+ STATS_LEAVE_INIT(vm->stats)
6264 return vm;
6365}
6466
65−void terminate(VM* vm) {
67+Stats terminate(VM* vm) {
68+ Stats stats = vm->stats;
69+ STATS_ENTER_EXIT(stats)
70+
6671 free(vm->inbox);
6772 free(vm->valstack);
6873 free(vm->intstack);
6974 free(vm->floatstack);
70−
7175 free_heap(&(vm->heap));
72−
7376 free(vm->argv);
7477
7578 pthread_mutex_destroy(&(vm -> inbox_lock));
7679 pthread_mutex_destroy(&(vm -> inbox_block));
7780 pthread_cond_destroy(&(vm -> inbox_waiting));
7881 free(vm);
82+
83+ STATS_LEAVE_EXIT(stats)
84+ return stats;
7985}
8086
8187void idris_requireAlloc(VM* vm, size_t size) {
@@ -111,7 +117,7 @@ void* allocate(VM* vm, size_t size, int outerlock) {
111117 size_t chunk_size = size + sizeof(size_t);
112118
113119 if (vm->heap.next + chunk_size < vm->heap.end) {
114− vm->allocations += chunk_size;
120+ STATS_ALLOC(vm->stats, chunk_size)
115121 void* ptr = (void*)(vm->heap.next + sizeof(size_t));
116122 *((size_t*)(vm->heap.next)) = chunk_size;
117123 vm->heap.next += chunk_size;
@@ -409,7 +415,9 @@ void* runThread(void* arg) {
409415 callvm->processes--;
410416
411417 free(td);
412− terminate(vm);
418+
419+ Stats stats = terminate(vm);
420+ // aggregate_stats(&(td->vm->stats), &stats);
413421 return NULL;
414422}
415423
@@ -501,12 +509,12 @@ void idris_sendMessage(VM* sender, VM* dest, VAL msg) {
501509 // So: we try to copy, if a collection happens, we do the copy again
502510 // under the assumption there's enough space this time.
503511
504− int gcs = dest->collections;
512+ int gcs = dest->stats.collections;
505513 pthread_mutex_lock(&dest->alloc_lock);
506514 VAL dmsg = copyTo(dest, msg);
507515 pthread_mutex_unlock(&dest->alloc_lock);
508516
509− if (dest->collections>gcs) {
517+ if (dest->stats.collections > gcs) {
510518 // a collection will have invalidated the copy
511519 pthread_mutex_lock(&dest->alloc_lock);
512520 dmsg = copyTo(dest, msg); // try again now there's room...
rts/idris_rts.h+4−4
@@ -9,8 +9,8 @@
99#include <pthread.h>
1010#include <stdint.h>
1111
12−#define IDRIS_DEBUG
1312#include "idris_heap.h"
13+#include "idris_stats.h"
1414
1515// Closures
1616
@@ -67,12 +67,12 @@ typedef struct {
6767
6868 int processes; // Number of child processes
6969 int max_threads; // maximum number of threads to run in parallel
70+
71+ Stats stats;
7072
7173 int argc;
7274 VAL* argv; // command line arguments
7375
74− int allocations;
75− int collections;
7676 VAL ret;
7777 VAL reg1;
7878} VM;
@@ -82,7 +82,7 @@ VM* init_vm(int stack_size, size_t heap_size,
8282 int max_threads,
8383 int argc, char* argv[]);
8484// Clean up a VM once it's no longer needed
85−void terminate(VM* vm);
85+Stats terminate(VM* vm);
8686
8787// Functions all take a pointer to their VM, and previous stack base,
8888// and return nothing.
rts/idris_stats.cnew file+53
@@ -0,0 +1,53 @@
1+#include "idris_stats.h"
2+
3+#include <stdio.h>
4+#include <locale.h>
5+
6+#ifdef IDRIS_ENABLE_STATS
7+
8+void print_stats(const Stats * stats) {
9+ clock_t total = clock() - stats->start_time;
10+ clock_t mut = total - stats->init_time - stats->gc_time - stats->exit_time;
11+ double mut_sec = (double)mut / CLOCKS_PER_SEC;
12+ int avg_chunk = (int)((double)stats->allocations / (double)stats->alloc_count);
13+ int alloc_rate = (int)((double)(stats->allocations) / mut_sec);
14+
15+ setlocale(LC_NUMERIC, "");
16+ printf("\n");
17+ printf("%'20d bytes allocated in the heap\n", stats->allocations);
18+ printf("%'20d bytes copied during GC\n", stats->copied);
19+ printf("%'20d maximum heap size\n", stats->max_heap_size);
20+ printf("%'20d chunks allocated in the heap\n", stats->alloc_count);
21+ printf("%'20d average chunk size\n\n", avg_chunk);
22+
23+ printf("GC called %d times\n\n", stats->collections);
24+
25+ printf("INIT time: %8.3fs\n", (double)stats->init_time / CLOCKS_PER_SEC);
26+ printf("MUT time: %8.3fs\n", mut_sec);
27+ printf("GC time: %8.3fs\n", (double)stats->gc_time / CLOCKS_PER_SEC);
28+ printf("EXIT time: %8.3fs\n", (double)stats->exit_time / CLOCKS_PER_SEC);
29+ printf("TOTAL time: %8.3fs\n\n", (double)total / CLOCKS_PER_SEC);
30+
31+ printf("%%GC time: %.2f%%\n\n", 100 * (double)stats->gc_time / (double)total);
32+
33+ printf("Alloc rate %'d bytes per MUT sec\n\n", alloc_rate);
34+
35+ printf("Productivity %.2f%%\n", 100 * ((double)mut / (double)total));
36+}
37+
38+void aggregate_stats(Stats * stats1, const Stats * stats2) {
39+ fprintf(stderr, "RTS error: aggregate_stats not implemented");
40+}
41+
42+#else
43+
44+void print_stats(const Stats * stats) {
45+ fprintf(stderr, "RTS ERROR: Stats are disabled.\n" \
46+ "By the way GC called %d times.\n", stats->collections);
47+}
48+
49+void aggregate_stats(Stats * stats1, const Stats * stats2) {
50+ stats1->collections += stats2->collections;
51+}
52+
53+#endif // IDRIS_ENABLE_STATS
rts/idris_stats.hnew file+73
@@ -0,0 +1,73 @@
1+#ifndef _IDRIS_STATS_H
2+#define _IDRIS_STATS_H
3+
4+#include <time.h>
5+
6+// Should not be defined in release.
7+#define IDRIS_ENABLE_STATS
8+
9+// TODO: measure user time, exclusive/inclusive stats
10+typedef struct {
11+#ifdef IDRIS_ENABLE_STATS
12+ int allocations; // Size of allocated space in bytes for all execution time.
13+ int alloc_count; // How many times alloc is called.
14+ int copied; // Size of space copied during GC.
15+ int max_heap_size; // Maximum heap size achieved.
16+
17+ clock_t init_time; // Time spent for vm initialization.
18+ clock_t exit_time; // Time spent for vm termination.
19+ clock_t gc_time; // Time spent for gc for all execution time.
20+ clock_t max_gc_pause; // Time spent for longest gc.
21+ clock_t start_time; // Time of rts entry point.
22+#endif // IDRIS_ENABLE_STATS
23+ int collections; // How many times gc called.
24+} Stats; // without start time it's a monoid, can we remove start_time it somehow?
25+
26+void print_stats(const Stats * stats);
27+void aggregate_stats(Stats * stats1, const Stats * stats2);
28+
29+
30+#ifdef IDRIS_ENABLE_STATS
31+
32+#ifndef MAX
33+#define MAX(a, b) ((a) > (b) ? (a) : (b))
34+#endif
35+
36+#define STATS_INIT_STATS(stats) \
37+ memset(&stats, 0, sizeof(Stats)); \
38+ stats.start_time = clock();
39+
40+#define STATS_ALLOC(stats, size) \
41+ stats.allocations += size; \
42+ stats.alloc_count = stats.alloc_count + 1;
43+
44+#define STATS_ENTER_INIT(stats) clock_t _start_time = clock();
45+#define STATS_LEAVE_INIT(stats) stats.init_time = clock() - _start_time;
46+
47+#define STATS_ENTER_EXIT(stats) clock_t _start_time = clock();
48+#define STATS_LEAVE_EXIT(stats) stats.exit_time = clock() - _start_time;
49+
50+#define STATS_ENTER_GC(stats, heap_size) \
51+ clock_t _start_time = clock(); \
52+ stats.max_heap_size = MAX(stats.max_heap_size, heap_size);
53+#define STATS_LEAVE_GC(stats, heap_size, heap_occuped) \
54+ clock_t _pause = clock() - _start_time; \
55+ stats.gc_time += _pause; \
56+ stats.max_gc_pause = MAX(_pause, stats.max_gc_pause); \
57+ stats.max_heap_size = MAX(stats.max_heap_size, heap_size); \
58+ stats.copied += heap_occuped; \
59+ stats.collections = stats.collections + 1;
60+
61+#else
62+#define STATS_INIT_STATS(stats) memset(&stats, 0, sizeof(Stats));
63+#define STATS_ENTER_INIT(stats)
64+#define STATS_LEAVE_INIT(stats)
65+#define STATS_ENTER_EXIT(stats)
66+#define STATS_LEAVE_EXIT(stats)
67+#define STATS_ALLOC(stats, size)
68+#define STATS_ENTER_GC(stats, heap_size)
69+#define STATS_LEAVE_GC(stats, heap_size, heap_occuped) \
70+ stats.collections = stats.collections + 1;
71+#endif // IDRIS_ENABLE_STATS
72+
73+#endif // _IDRIS_STATS_H