on master help sign in
A bit more detailed rts stats.
6f8ee96Sam T
rts/Makefile+3−2
@@ -1,8 +1,9 @@
1include ../config.mk
1include ../config.mk
2
2
3−OBJS = idris_rts.o idris_heap.o idris_gc.o idris_gmp.o idris_stdfgn.o idris_bitstring.o idris_opts.o
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
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
5CFLAGS = -O2 -Wall
5CFLAGS = -O2 -Wall
6+
6ifneq ($(GMP_INCLUDE_DIR),)
7ifneq ($(GMP_INCLUDE_DIR),)
7 CFLAGS += -isystem $(GMP_INCLUDE_DIR)
8 CFLAGS += -isystem $(GMP_INCLUDE_DIR)
8endif
9endif
rts/idris_gc.c+5−8
@@ -81,6 +81,7 @@ void cheney(VM *vm) {
81
81
82void idris_gc(VM* vm) {
82void idris_gc(VM* vm) {
83 HEAP_CHECK(vm)
83 HEAP_CHECK(vm)
84+ STATS_ENTER_GC(vm->stats, vm->heap.size)
84 // printf("Collecting\n");
85 // printf("Collecting\n");
85
86
86 char* newheap = malloc(vm->heap.size);
87 char* newheap = malloc(vm->heap.size);
@@ -92,8 +93,6 @@ void idris_gc(VM* vm) {
92 vm->heap.next = newheap;
93 vm->heap.next = newheap;
93 vm->heap.end = newheap + vm->heap.size;
94 vm->heap.end = newheap + vm->heap.size;
94
95
95− vm->collections++;
96−
97 VAL* root;
96 VAL* root;
98
97
99 for(root = vm->valstack; root < vm->valstack_top; ++root) {
98 for(root = vm->valstack; root < vm->valstack_top; ++root) {
@@ -118,16 +117,14 @@ void idris_gc(VM* vm) {
118 }
117 }
119 vm->heap.old = oldheap;
118 vm->heap.old = oldheap;
120
119
121− // gcInfo(vm, 0);
120+ STATS_LEAVE_GC(vm->stats, vm->heap.size, vm->heap.next - vm->heap.heap)
122 HEAP_CHECK(vm)
121 HEAP_CHECK(vm)
123}
122}
124
123
125void idris_gcInfo(VM* vm, int doGC) {
124void idris_gcInfo(VM* vm, int doGC) {
126− printf("\nStack: %p %p\n", vm->valstack, vm->valstack_top);
125+ printf("Stack: <BOT %p> <TOP %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));
126+ printf("Final heap size %d\n", (int)(vm->heap.size));
130− printf("Final heap use %d\n", (int)(vm->heap.next - vm->heap.heap));
127+ printf("Final heap use %d\n", (int)(vm->heap.next - vm->heap.heap));
131 if (doGC) { idris_gc(vm); }
128 if (doGC) { idris_gc(vm); }
132 printf("Final heap use after GC %d\n", (int)(vm->heap.next - vm->heap.heap));
129 printf("Final heap use after GC %d\n", (int)(vm->heap.next - vm->heap.heap));
133}
130}
rts/idris_heap.h+1−2
@@ -8,10 +8,9 @@ typedef struct {
8 char* heap; // Point to bottom of heap
8 char* heap; // Point to bottom of heap
9 char* end; // Point to top of heap
9 char* end; // Point to top of heap
10 size_t size; // Size of _next_ heap. Size of current heap is /end - heap/.
10 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.
12
12
13 char* old;
13 char* old;
14− // TODO heap usage
15} Heap;
14} Heap;
16
15
17
16
rts/idris_main.c+11−2
@@ -1,5 +1,6 @@
1#include "idris_opts.h"
1#include "idris_opts.h"
2−
2+#include "idris_stats.h"
3+#include "idris_rts.h"
3// The default options should give satisfactory results under many circumstances.
4// The default options should give satisfactory results under many circumstances.
4RTSOpts opts = {
5RTSOpts opts = {
5 .init_heap_size = 4096000,
6 .init_heap_size = 4096000,
@@ -13,9 +14,17 @@ int main(int argc, char* argv[]) {
13 VM* vm = init_vm(opts.max_stack_size, opts.init_heap_size, 1, argc, argv);
14 VM* vm = init_vm(opts.max_stack_size, opts.init_heap_size, 1, argc, argv);
14 _idris__123_runMain0_125_(vm, NULL);
15 _idris__123_runMain0_125_(vm, NULL);
15
16
17+#ifdef IDRIS_DEBUG
16 if (opts.show_summary) {
18 if (opts.show_summary) {
17 idris_gcInfo(vm, 1);
19 idris_gcInfo(vm, 1);
18 }
20 }
21+#endif
22+
23+ Stats stats = terminate(vm);
24+
25+ if (opts.show_summary) {
26+ print_stats(&stats);
27+ }
19
28
20− terminate(vm);
29+ return EXIT_SUCCESS;
21}
30}
rts/idris_rts.c+21−13
@@ -14,11 +14,15 @@
14VM* init_vm(int stack_size, size_t heap_size,
14VM* init_vm(int stack_size, size_t heap_size,
15 int max_threads, // not implemented yet
15 int max_threads, // not implemented yet
16 int argc, char* argv[]) {
16 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));
20
17
21 VM* vm = malloc(sizeof(VM));
18 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+
22 vm->valstack = valstack;
26 vm->valstack = valstack;
23 vm->valstack_top = valstack;
27 vm->valstack_top = valstack;
24 vm->valstack_base = valstack;
28 vm->valstack_base = valstack;
@@ -30,9 +34,6 @@ VM* init_vm(int stack_size, size_t heap_size,
30
34
31 alloc_heap(&(vm->heap), heap_size);
35 alloc_heap(&(vm->heap), heap_size);
32
36
33− vm->collections = 0;
34− vm->allocations = 0;
35−
36 vm->ret = NULL;
37 vm->ret = NULL;
37 vm->reg1 = NULL;
38 vm->reg1 = NULL;
38
39
@@ -59,23 +60,28 @@ VM* init_vm(int stack_size, size_t heap_size,
59 vm->argv[i] = MKSTR(vm, argv[i]);
60 vm->argv[i] = MKSTR(vm, argv[i]);
60 }
61 }
61
62
63+ STATS_LEAVE_INIT(vm->stats)
62 return vm;
64 return vm;
63}
65}
64
66
65−void terminate(VM* vm) {
67+Stats terminate(VM* vm) {
68+ Stats stats = vm->stats;
69+ STATS_ENTER_EXIT(stats)
70+
66 free(vm->inbox);
71 free(vm->inbox);
67 free(vm->valstack);
72 free(vm->valstack);
68 free(vm->intstack);
73 free(vm->intstack);
69 free(vm->floatstack);
74 free(vm->floatstack);
70−
71 free_heap(&(vm->heap));
75 free_heap(&(vm->heap));
72−
73 free(vm->argv);
76 free(vm->argv);
74
77
75 pthread_mutex_destroy(&(vm -> inbox_lock));
78 pthread_mutex_destroy(&(vm -> inbox_lock));
76 pthread_mutex_destroy(&(vm -> inbox_block));
79 pthread_mutex_destroy(&(vm -> inbox_block));
77 pthread_cond_destroy(&(vm -> inbox_waiting));
80 pthread_cond_destroy(&(vm -> inbox_waiting));
78 free(vm);
81 free(vm);
82+
83+ STATS_LEAVE_EXIT(stats)
84+ return stats;
79}
85}
80
86
81void idris_requireAlloc(VM* vm, size_t size) {
87void idris_requireAlloc(VM* vm, size_t size) {
@@ -111,7 +117,7 @@ void* allocate(VM* vm, size_t size, int outerlock) {
111 size_t chunk_size = size + sizeof(size_t);
117 size_t chunk_size = size + sizeof(size_t);
112
118
113 if (vm->heap.next + chunk_size < vm->heap.end) {
119 if (vm->heap.next + chunk_size < vm->heap.end) {
114− vm->allocations += chunk_size;
120+ STATS_ALLOC(vm->stats, chunk_size)
115 void* ptr = (void*)(vm->heap.next + sizeof(size_t));
121 void* ptr = (void*)(vm->heap.next + sizeof(size_t));
116 *((size_t*)(vm->heap.next)) = chunk_size;
122 *((size_t*)(vm->heap.next)) = chunk_size;
117 vm->heap.next += chunk_size;
123 vm->heap.next += chunk_size;
@@ -409,7 +415,9 @@ void* runThread(void* arg) {
409 callvm->processes--;
415 callvm->processes--;
410
416
411 free(td);
417 free(td);
418+
412− terminate(vm);
419+ Stats stats = terminate(vm);
420+ // aggregate_stats(&(td->vm->stats), &stats);
413 return NULL;
421 return NULL;
414}
422}
415
423
@@ -501,12 +509,12 @@ void idris_sendMessage(VM* sender, VM* dest, VAL msg) {
501 // So: we try to copy, if a collection happens, we do the copy again
509 // So: we try to copy, if a collection happens, we do the copy again
502 // under the assumption there's enough space this time.
510 // under the assumption there's enough space this time.
503
511
504− int gcs = dest->collections;
512+ int gcs = dest->stats.collections;
505 pthread_mutex_lock(&dest->alloc_lock);
513 pthread_mutex_lock(&dest->alloc_lock);
506 VAL dmsg = copyTo(dest, msg);
514 VAL dmsg = copyTo(dest, msg);
507 pthread_mutex_unlock(&dest->alloc_lock);
515 pthread_mutex_unlock(&dest->alloc_lock);
508
516
509− if (dest->collections>gcs) {
517+ if (dest->stats.collections > gcs) {
510 // a collection will have invalidated the copy
518 // a collection will have invalidated the copy
511 pthread_mutex_lock(&dest->alloc_lock);
519 pthread_mutex_lock(&dest->alloc_lock);
512 dmsg = copyTo(dest, msg); // try again now there's room...
520 dmsg = copyTo(dest, msg); // try again now there's room...
rts/idris_rts.h+4−4
@@ -9,8 +9,8 @@
9#include <pthread.h>
9#include <pthread.h>
10#include <stdint.h>
10#include <stdint.h>
11
11
12−#define IDRIS_DEBUG
13#include "idris_heap.h"
12#include "idris_heap.h"
13+#include "idris_stats.h"
14
14
15// Closures
15// Closures
16
16
@@ -67,12 +67,12 @@ typedef struct {
67
67
68 int processes; // Number of child processes
68 int processes; // Number of child processes
69 int max_threads; // maximum number of threads to run in parallel
69 int max_threads; // maximum number of threads to run in parallel
70+
71+ Stats stats;
70
72
71 int argc;
73 int argc;
72 VAL* argv; // command line arguments
74 VAL* argv; // command line arguments
73
75
74− int allocations;
75− int collections;
76 VAL ret;
76 VAL ret;
77 VAL reg1;
77 VAL reg1;
78} VM;
78} VM;
@@ -82,7 +82,7 @@ VM* init_vm(int stack_size, size_t heap_size,
82 int max_threads,
82 int max_threads,
83 int argc, char* argv[]);
83 int argc, char* argv[]);
84// Clean up a VM once it's no longer needed
84// Clean up a VM once it's no longer needed
85−void terminate(VM* vm);
85+Stats terminate(VM* vm);
86
86
87// Functions all take a pointer to their VM, and previous stack base,
87// Functions all take a pointer to their VM, and previous stack base,
88// and return nothing.
88// 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