1/*
2 * Part of Scheme 48 1.9.  See file COPYING for notices and license.
3 *
4 * Authors: David Frese, Christos Freris, Eric Knauel
5 */
6
7/* This file needs to be included from generation_gc.c, because for
8   reasons of simplicity we use static variables from there directly
9   here. */
10
11/* Not really sure if this is true:
12
13   MEASURE_GC was an old flag by Norbert, which activated writing out
14   several files with Sexps, containing the size of the heap, the
15   areas, and some timing information. Most (all?) of it is actually
16   stripped off here with "#if 0".
17
18   S48_MEASURE_GC_TIME is the newer flag by Christos, used to write
19   out gnuplot files with detailed timing informations and size
20   informations that are taking out of the same variables as
21   MEASURE_GC did.
22
23   DISPLAY_MEASURE_GC additionally prints out some infos to stdout
24   about what's going on with the measurement.
25
26   This should be made less confusing and working properly.
27
28   -- David
29*/
30
31FILE* datafile;
32
33/* controlled by s48_collect: */
34void start_measure() {
35  datafile = fopen("MEASURE-GC", "a");
36  fprintf(datafile, " ( ");
37}
38
39void stop_measure() {
40  fprintf(datafile, " ) \n \n");
41  fclose(datafile);
42}
43
44static unsigned long count_collection = 0;
45
46/* write-barrier and inter-generational-pointer */
47static unsigned int count_wb = 0;
48static unsigned int count_gc_wb = 0;
49static unsigned int count_igp = 0;
50static unsigned int count_gc_igp = 0;
51
52
53/* visited and passed areas from trace_areas_roots */
54
55static unsigned long  count_areas_roots_visited = 0;
56static unsigned long  count_areas_roots_passed = 0;
57
58/* the heap usage and size */
59
60static unsigned long count_heap_size = 0;
61static unsigned long count_heap_usage = 0;
62
63
64static unsigned long old_heap_size = 0;
65
66unsigned long get_wbarrier() {
67  return count_wb;
68}
69
70unsigned long get_gc_wbarrier() {
71  return count_gc_wb;
72}
73
74unsigned long get_igen() {
75  return count_igp;
76}
77
78unsigned long get_gc_igen() {
79  return count_gc_igp;
80}
81
82
83int write_area_size(int size, int gens[]){
84  int i;
85
86  fprintf(datafile, " (areasize ");
87
88  /* the creation space: */
89  fprintf(datafile, " %d ", gens[size]);
90
91  for(i = 0; i < size; i++){
92
93    /* the generations: */
94    fprintf(datafile, " %d ", gens[i]);
95  }
96  fprintf(datafile, " ) ");
97
98  return 0;
99}
100
101
102
103/* mark_cons ratio */
104int write_mc_ratio() {
105  double r = ((double) count_heap_usage) /
106    ((double) (count_heap_size - count_heap_usage));
107  fprintf(datafile, " (mcratio ");
108  fprintf(datafile, " %f", r);
109  fprintf(datafile, " ) ");
110
111  return 0;
112}
113
114int write_heap_usage_size(){
115  fprintf(datafile, " (heap ");
116  fprintf(datafile, " %d ", count_heap_size);
117  fprintf(datafile, " %d ", count_heap_usage);
118  fprintf(datafile, " ) ");
119
120  return 0;
121}
122
123/*sum of write-barrier calls and created inter-generational-pointer*/
124int write_wb_igp(){
125  fprintf(datafile, " (wb ");
126  fprintf(datafile, " %d", count_wb);
127  fprintf(datafile, " %d", count_igp);
128  fprintf(datafile, " ) ");
129  return 0;
130}
131
132/* which generation is collected */
133int write_minor_major_gc(int n){
134  fprintf(datafile, " (gens ");
135  fprintf(datafile, " %d ", n); /* collect the first n gens */
136  fprintf(datafile, " %d ", count_collection); /* collection number */
137  fprintf(datafile, " ) ");
138
139  return 0;
140}
141
142/* ratio of vistied/passed areas in trace_areas_roots */
143int write_areas_roots_ratio(){
144  double ratio = ((((double) count_areas_roots_passed)  /
145		   ((double) count_areas_roots_visited)) * 100);
146  fprintf(datafile, " (arearoots ");
147  fprintf(datafile, " %f ", ratio);
148  fprintf(datafile, " ) ");
149  return 0;
150}
151
152
153/* -- the "#ifdef" functions: -- */
154
155
156/* writing some data just before the collection:*/
157
158
159/************************************************************************
160called in: <file>::<function>
161./c/bibop/generation_gc.c::s48_collect
162*************************************************************************/
163void measure_gc_start(int c){
164  count_collection++;
165
166  if (old_heap_size < count_heap_size){
167      old_heap_size = count_heap_size;
168  }
169
170  start_measure();  /* opens fileport */
171  write_minor_major_gc(c);
172  write_heap_usage_size();
173
174  /* small and large area numbers are invoked in s48_collect*/
175}
176
177/* next gc (in generation n) is triggerd and finished */
178/************************************************************************
179called in: <file>::<function>
180./c/bibop/generation_gc.c::s48_collect
181*************************************************************************/
182void measure_gc_end() {
183  write_mc_ratio();
184  write_heap_usage_size();
185  write_wb_igp();
186  write_areas_roots_ratio();
187  stop_measure();  /* closes fileport */
188}
189
190
191/************************************************************************
192called in: ./c/bibop/area_roots.c::s48_write_barrier
193*************************************************************************/
194void measure_write_barrier(char flag) {
195  if (flag){
196    /* so we have a inter-gen-pointer..*/
197    count_igp++;
198  }
199  count_wb++;
200}
201
202/************************************************************************
203called in:./c/bibop/area_roots.c::s48_write_internal_barrier
204*************************************************************************/
205void measure_gc_write_barrier() {
206    /* when we call this we have a new inter-gen-pointer..*/
207    count_gc_igp++;
208    count_gc_wb++;
209}
210
211
212/* number of small/large areas per generation */
213/************************************************************************
214called in: <file>::<function>
215./c/bibop/generation_gc.c::get_area_objects
216*************************************************************************/
217void measure_small_areas(int size, int small[]){
218
219  write_area_size(size, small);
220}
221
222/************************************************************************
223called in: <file>::<function>
224./c/bibop/generation_gc.c::get_area_objects
225*************************************************************************/
226void measure_large_areas(int size, int large[]){
227
228  write_area_size(size, large);
229}
230
231/* get the data from trace_areas_roots() */
232/************************************************************************
233called in: <file>::<function>
234./c/bibop/area_roots.c::s48_trace_areas_roots
235*************************************************************************/
236void measure_areas_roots(unsigned long visited, unsigned long passed){
237  count_areas_roots_visited += visited;
238  count_areas_roots_passed += passed;
239}
240
241/************************************************************************
242called in: <file>::<function>
243./c/bibop/generation_gc.c::s48_collect
244*************************************************************************/
245void measure_heap_size(unsigned long size){
246  count_heap_size = size;
247}
248
249/************************************************************************
250called in: ./c/bibop/generation_gc.c::s48_collect
251*************************************************************************/
252void measure_heap_usage(unsigned long usage){
253  count_heap_usage = usage;
254}
255
256/************************************************************************
257called in: ./c/bibop/generation_gc.c::s48_collect
258*************************************************************************/
259void  clear_measurement(){
260
261  count_wb = 0;
262  count_igp = 0;
263  count_areas_roots_passed = 0;
264  count_areas_roots_visited = 0;
265
266  count_gc_wb = 0;
267  count_gc_igp = 0;
268
269}
270
271unsigned long get_areas_size(Area* areas) {
272  unsigned long size = 0;
273  FOR_ALL_AREAS(areas,
274		size += (area->frontier - area->start));
275  return size;
276}
277
278typedef struct {
279  unsigned long gen_small_current;  /* generation small area current */
280  unsigned long gen_small_other;    /* generation small area other */
281  unsigned long gen_large_current;  /* generation large area current */
282  unsigned long gen_large_other;    /* generation large area other */
283  unsigned long gen_weaks_current;  /* generation weaks area current */
284  unsigned long gen_weaks_other;    /* generation weaks area other */
285} GenImg;
286
287typedef struct {
288  unsigned long gc_nr;           /* collection number */
289  unsigned long cs_small_below;  /* creation space small below area */
290  unsigned long cs_small_above;  /* creation space small above area */
291  unsigned long cs_large;        /* creation space large area */
292  unsigned long cs_weaks;        /* creation space weaks area */
293  unsigned long wbarrier;        /* write barrier calls */
294  unsigned long igen;            /* intergenerational pointers (old->young) */
295  unsigned long gc_wbarrier;     /* internal write barrier calls */
296  unsigned long gc_igen;         /* internal intergenerational pointers (old->young) */
297
298  /* Generations */
299  GenImg genImgs[S48_GENERATIONS_COUNT];
300} HeapImg;
301
302void takeHeapImg(HeapImg* hi) {
303  int i;
304
305  hi->gc_nr          = s48_gc_count();
306  hi->cs_small_below = get_areas_size(creation_space.small_below);
307  hi->cs_small_above = get_areas_size(creation_space.small_above);
308  hi->cs_large       = get_areas_size(creation_space.large);
309  hi->cs_weaks       = get_areas_size(creation_space.weaks);
310  hi->wbarrier       = get_wbarrier();      /* measure.h */
311  hi->gc_wbarrier    = get_gc_wbarrier();   /* measure.h */
312  hi->igen           = get_igen();          /* measure.h */
313  hi->gc_igen        = get_gc_igen();       /* measure.h */
314
315  for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
316    hi->genImgs[i].gen_small_current =
317      get_areas_size(generations[i].current_space->small_area);
318    hi->genImgs[i].gen_small_other   =
319      get_areas_size(generations[i].other_space->small_area);
320    hi->genImgs[i].gen_large_current =
321      get_areas_size(generations[i].current_space->large_area);
322    hi->genImgs[i].gen_large_other   =
323      get_areas_size(generations[i].other_space->large_area);
324    hi->genImgs[i].gen_weaks_current =
325      get_areas_size(generations[i].current_space->weaks_area);
326    hi->genImgs[i].gen_weaks_other   =
327      get_areas_size(generations[i].other_space->weaks_area);
328  }
329}
330
331#if (DISPLAY_MEASURE_GC)
332
333void display_string(char* message) {
334  fprintf(stdout, message);
335}
336
337void display_string_x(char* message, int times) {
338  while (times > 0) {
339    display_string(message);
340    times--;
341  }
342}
343
344void display_number(int digits, long number) {
345  fprintf(stdout, " %0*d", digits, number);
346}
347
348void display_double(int digits, double n) {
349  fprintf(stdout, " %0*.*f", digits, 3, n);
350}
351
352void newline() {
353  fprintf(stdout, "\n");
354}
355
356void space() {
357  fprintf(stdout, " ");
358}
359
360void dis_string(char* message) {
361  display_string(message);
362  newline();
363}
364
365void dis_string_x(char* message, int times) {
366  display_string_x(message, times);
367  newline();
368}
369
370void dis_number(int digits, long n) {
371  display_number(digits, n);
372  newline();
373}
374
375void dis_double(int digits, double n) {
376  display_double(digits, n);
377  newline();
378}
379
380void display_comparison(long new, long old) {
381  if (new == old) {
382    display_string("  ");
383  }
384  else if (new > old) {
385    display_string(" +");
386  }
387  else display_string(" -");
388}
389
390void write_vm_options(FILE* f) {
391    fprintf(f,
392	    "VM (scheme48) Compiled with these Options\n"
393	    "-----------------------------------------\n"
394	    "S48_MEASURE_GC_TIME: %02d\n"
395	    "MEASURE_GC: %02d\n"
396	    "DISPLAY_MEASURE_GC: %02d\n"
397	    "S48_GENERATIONS_COUNT: %03d\n"
398	    "S48_CREATION_SPACE_SIZE: %03d\n"
399	    "S48_DEFAULT_WATER_MARK: %03d\n"
400	    "S48_ADJUST_WATER_MARK: %02d\n"
401	    "S48_SMALL_OBJECT_LIMIT: %05d\n"
402	    "S48_MINIMUM_SMALL_AREA_SIZE: %03d\n"
403	    "S48_MAXIMUM_SMALL_AREA_SIZE: %03d\n"
404	    "S48_MAXIMUM_LARGE_CREATION_SPACE_SIZE: %05d\n"
405	    "S48_MINIMUM_WEAK_AREA_SIZE: %05d\n"
406	    "S48_MAXIMUM_WEAK_AREA_SIZE: %05d\n"
407	    "S48_COLLECTION_THRESHOLD: %05d\n"
408	    "S48_LOG_CARD_SIZE: %03d\n"
409	    "S48_DIRTY_VECTOR_METHOD: %02d\n"
410	    "S48_WRITE_BARRIER_COMPLEXITY: %02d\n"
411	    "S48_USE_CARD_GENERATION_INDEXING: %02d\n"
412	    "S48_USE_GENERATION_INDEXING: %02d\n"
413	    "S48_USE_REMEMBERED_SETS: %02d\n",
414	    S48_MEASURE_GC_TIME,
415	    MEASURE_GC,
416	    DISPLAY_MEASURE_GC,
417	    S48_GENERATIONS_COUNT,
418	    S48_CREATION_SPACE_SIZE,
419	    S48_DEFAULT_WATER_MARK,
420	    S48_ADJUST_WATER_MARK,
421	    S48_SMALL_OBJECT_LIMIT,
422	    S48_MINIMUM_SMALL_AREA_SIZE,
423	    S48_MAXIMUM_SMALL_AREA_SIZE,
424	    S48_MAXIMUM_LARGE_CREATION_SPACE_SIZE,
425	    S48_MINIMUM_WEAK_AREA_SIZE,
426	    S48_MAXIMUM_WEAK_AREA_SIZE,
427	    S48_COLLECTION_THRESHOLD,
428	    S48_LOG_CARD_SIZE,
429	    S48_DIRTY_VECTOR_METHOD,
430	    S48_WRITE_BARRIER_COMPLEXITY,
431	    S48_USE_CARD_GENERATION_INDEXING,
432	    S48_USE_GENERATION_INDEXING,
433	    S48_USE_REMEMBERED_SETS);
434
435#if (S48_USE_REMEMBERED_SETS)
436    fprintf(f,
437	    "S48_REMEMBERED_SET_SIZE: %05d\n"
438	    "S48_REMEMBERED_SET_TYPE: %02d\n"
439	    "S48_UNIQUE_REMEMBERED_SET: %02d\n",
440	    S48_REMEMBERED_SET_SIZE,
441	    S48_REMEMBERED_SET_TYPE,
442	    S48_UNIQUE_REMEMBERED_SET);
443
444#endif /* #if (S48_USE_REMEMBERED_SETS) */
445
446    fprintf(f,
447	    "S48_USE_RDM: %02d\n",
448	    S48_USE_RDM);
449
450#if (S48_USE_RDM)
451    fprintf(f,
452	    "S48_RDM_MAX_SIZE: %05d\n"
453	    "S48_RDM_INITIAL_THRESHOLD: %05d\n"
454	    "S48_RDM_MIN_THRESHOLD: %05d",
455	    S48_RDM_MAX_SIZE,
456	    S48_RDM_INITIAL_THRESHOLD,
457	    S48_RDM_MIN_THRESHOLD);
458#endif /* #if (S48_USE_RDM) */
459
460    fprintf(f, "\n\n");
461}
462
463void display_vm_options() {
464  write_vm_options(stdout);
465}
466
467#endif
468
469
470FILE* file;
471
472static unsigned long gc_nr = 0;
473
474static double gc_time = 0;
475static double gc_runtime = 0;
476static unsigned long total_gc_time_in_usec = 0;
477static double gc_average_time = 0;
478
479static unsigned long heap_size_before = 0;
480static unsigned long heap_size_after = 0;
481static unsigned long max_heap = 0;
482
483static unsigned long s48_heap_size_before = 0;
484static unsigned long s48_heap_size_after = 0;
485
486static HeapImg heap_img_before;
487static HeapImg heap_img_after;
488
489static unsigned long all_surviving_obj = 0;
490static unsigned long first_time_flag = 0;
491
492void fprint_cs_data(FILE* f, HeapImg* img_before, HeapImg* img_after) {
493  fprintf(f, "%8i %8i %8i %8i %8i %8i %8i %8i ",
494	  heap_img_before.cs_small_below,           /* 9 */
495	  heap_img_after.cs_small_below,            /* 10 */
496	  heap_img_before.cs_small_above,           /* 11 */
497	  heap_img_after.cs_small_above,            /* 12 */
498	  heap_img_before.cs_large,                 /* 13 */
499	  heap_img_after.cs_large,                  /* 14 */
500	  heap_img_before.cs_weaks,                 /* 15 */
501	  heap_img_after.cs_weaks                   /* 16 */
502	  );
503}
504
505/* wi_data = write barrier & intergenerational pointers */
506void fprint_wi_data(FILE* f, HeapImg* img_before, HeapImg* img_after) {
507  fprintf(f, "%8i %8i %8i %8i",
508	  heap_img_before.wbarrier,                 /* 17 */
509	  heap_img_after.gc_wbarrier,               /* 18 */
510	  heap_img_before.igen,                     /* 19 */
511	  heap_img_after.gc_igen                    /* 20 */
512	  );
513}
514
515void fprint_gen_data(FILE* f, HeapImg* img_before, HeapImg* img_after) {
516  int i;
517
518  /* Line Order: 20 + ( X * i+1)
519     example:
520     Line Order of: img_after->genImgs[1].gen_large_current [ 6 ]
521     Is: 20 + ( 6 * 1+1) = 32
522  */
523
524  for (i = 0; i < S48_GENERATIONS_COUNT; i++) {
525    fprintf(f, "%8i %8i %8i %8i %8i %8i %8i %8i %8i %8i %8i %8i ", /* X */
526	    img_before->genImgs[i].gen_small_current,  /* 1  */
527	    img_after->genImgs[i].gen_small_current,   /* 2  */
528	    img_before->genImgs[i].gen_small_other,    /* 3  */
529	    img_after->genImgs[i].gen_small_other,     /* 4  */
530	    img_before->genImgs[i].gen_large_current,  /* 5  */
531	    img_after->genImgs[i].gen_large_current,   /* 6  */
532	    img_before->genImgs[i].gen_large_other,    /* 7  */
533	    img_after->genImgs[i].gen_large_other,     /* 8  */
534	    img_before->genImgs[i].gen_weaks_current,  /* 9  */
535	    img_after->genImgs[i].gen_weaks_current,   /* 10  */
536	    img_before->genImgs[i].gen_weaks_other,    /* 11  */
537	    img_after->genImgs[i].gen_weaks_other      /* 12 */
538	    );
539  }
540}
541
542void fprint_all_data (FILE* f, HeapImg* img_before, HeapImg* img_after){
543
544  /* Creation Space */
545  fprint_cs_data(f, img_before, img_after);
546
547  /* Write Barrier & InterGen Pointers */
548  fprint_wi_data(f, img_before, img_after);
549
550  /* Generations */
551  fprint_gen_data(f, img_before, img_after);
552}
553
554
555int get_small_objects(int gen){
556  int number = 0;
557  /* little cheat to get to the creation_space*/
558  if(gen == S48_GENERATIONS_COUNT){
559    FOR_ALL_AREAS(creation_space.small_below, number += 1);
560    FOR_ALL_AREAS(creation_space.small_above, number += 1);
561  }else{
562    FOR_ALL_AREAS(generations[gen].current_space->small_area, number += 1);
563  }
564  return number;
565}
566
567int get_large_objects(int gen){
568  int number = 0;
569  if(gen == S48_GENERATIONS_COUNT){
570    FOR_ALL_AREAS(creation_space.large, number += 1);
571  }else{
572    FOR_ALL_AREAS(generations[gen].current_space->large_area, number +=1);
573  }
574  return number;
575}
576
577void get_area_objects(){
578  int small[S48_GENERATIONS_COUNT+1];
579  int large[S48_GENERATIONS_COUNT+1];
580  int i;
581  for (i = 0; i <= S48_GENERATIONS_COUNT; i++){
582    small[i] = get_small_objects(i);
583    large[i] = get_large_objects(i);
584  }
585  measure_small_areas(S48_GENERATIONS_COUNT, small);
586  measure_large_areas(S48_GENERATIONS_COUNT, large);
587}
588
589
590long time_swap;
591struct timeval t1;
592struct timeval t2;
593struct timeval t3;
594
595void measure_before_collection(int c) {
596#if 0
597  measure_gc_start(c);
598  all_surviving_obj = 0;
599  get_area_objects();
600  measure_heap_size(s48_heap_size());
601  measure_heap_usage(s48_heap_live_size());
602#endif
603
604  /* catch the actual heap status */
605  takeHeapImg(&heap_img_before);
606  heap_size_before = s48_heap_size();
607  s48_heap_size_before = s48_heap_live_size();
608
609  /* catch the time before ...  */
610  gettimeofday(&t1, 0);
611}
612
613void measure_after_collection(int c) {
614  gettimeofday(&t2, 0);
615
616  t3.tv_sec = (t2.tv_sec - t1.tv_sec);
617  time_swap = t2.tv_usec - t1.tv_usec;
618  if (time_swap < 0) {
619    time_swap = 1000000 + time_swap;
620    t3.tv_sec -= 1;
621  }
622  t3.tv_usec = time_swap;
623
624  /* save some values after collection */
625  gc_nr = s48_gc_count();
626  total_gc_time_in_usec += t3.tv_usec;
627  gc_time =  t3.tv_usec / 1000000.0;
628  gc_runtime = total_gc_time_in_usec / 1000000.0;
629  gc_average_time = total_gc_time_in_usec / ( 1000000.0 * gc_nr) ;
630
631  takeHeapImg(&heap_img_after);
632  heap_size_after = s48_heap_size();
633  s48_heap_size_after = s48_heap_live_size();
634
635  max_heap = int_max(max_heap, int_max(heap_size_before, heap_size_after));
636
637#if 0
638  measure_heap_size(s48_heap_size());
639  measure_heap_usage(s48_heap_live_size());
640  measure_gc_end();  /* This will null wb and igp counters */
641#endif
642
643#if 0
644  file = fopen("MEASURE-GC-TIME", "a");
645  fprintf(file, "( %d ", t3.tv_sec);
646  fprintf(file, " %d )", t3.tv_usec);
647  fclose(file);
648#endif
649
650  file = fopen("MEASURE_GC_RESULT_TEMP", "w"); /* w : to overwrite */
651  fprintf(file, "%5i %5i %6.3f %6.3f %6.3f %8i %8i %8i ",
652	  gc_nr,                                    /* 1 */
653	  c,                                        /* 2 up to collected gen */
654	  gc_time,                                  /* 3 */
655	  gc_runtime,                               /* 4 */
656          gc_average_time,                          /* 5 */
657	  heap_size_before,                         /* 6 */
658	  heap_size_after,                          /* 7 */
659	  max_heap                                  /* 8 */
660	  );
661  fprint_all_data(file, &heap_img_before, &heap_img_after);
662  fprintf(file, "\n");  /*newline */
663  fclose(file);
664
665  /* Save all results in an extra file (not to overwrite) */
666  system("cat MEASURE_GC_RESULT_TEMP >> MEASURE_ALL_GC_RESULT"); /* unistd.h */
667
668#if (DISPLAY_MEASURE_GC)
669  /*Print config-options once */
670  if (first_time_flag == 0) {
671    first_time_flag = 1;
672    display_vm_options();
673    newline();
674    dis_string("gc_nr gen_nr gc_time gc_runtime gc_average");
675    dis_string_x("-", 40);
676  }
677
678  display_number(5, s48_gc_count() );
679  display_double(5, gc_time );
680  display_double(7, gc_runtime );
681  display_double(5, gc_average_time );
682
683  /* up to collected generations */
684  display_number(2, c );
685
686  /* the whole heap */
687  display_number(8, heap_size_before);
688  display_number(8, heap_size_after);
689  display_comparison(heap_size_after, heap_size_before);
690
691  /* the used heap */
692  display_number(8, s48_heap_size_before);
693  display_number(8, s48_heap_size_after);
694  display_comparison(s48_heap_size_after, s48_heap_size_before);
695
696  /* % relationship between the whole and the used heap */
697  display_double(5, (s48_heap_size_after * 100.0 ) / heap_size_after);
698
699  newline();
700  /*dis_string_x("-", 65); */
701  /*newline(); */
702
703  /*  s48_check_heap(0);*/
704
705  /* Initializes static variables: count_igp, count_wb, count_gc_igp,
706     count_gc_wb (measure.h) */
707    clear_measurement();
708#endif
709
710}
711