gc_tracer 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 02c2e3a73f9c81c909ea34661ee28e724e46ae6a
4
- data.tar.gz: f9ecb1757af0bf11518f6a4bf0065568fc1f6d78
3
+ metadata.gz: 7ad7a07f89e6474de38728bba4e183173133c727
4
+ data.tar.gz: 1be0ad94f2746c7fee8880725827a386cde7ef75
5
5
  SHA512:
6
- metadata.gz: c442b07afc88814c7dd2687872ba1a260bd6cfd26951596b488291fb31e06787265c1c9c2d1db353be6c712cfa209bfb91dc900a73e747d946d8ea4d7ab30b1d
7
- data.tar.gz: ccb123ceff8944ef0405c37793d192eabbc8d515c364da02aaf5ca1b3ec4872c82487467a946a96264f18d3237fb1168b2f03318f89b6e1fc35aeb9905517676
6
+ metadata.gz: b3410157161b046b7870da5caae27c0be60968c825f38908a18907e7ee8941effa28240e32f05ce769a5ad459064ec9784b0ec42746c989d486b2b2a65805c45
7
+ data.tar.gz: a168bf9cd168fbc5d4c80eacfb44d4b7dcc52053f5ba89bf821bb7a372dd874e9b06ed65073c21a02eda04b34321d6ee484a06513d5d42dac8b4cb95b053200c
data/README.md CHANGED
@@ -72,10 +72,36 @@ If you have netpbm package and pnmtopng command,
72
72
  bin/objspace_recorder_convert.rb converts all ppm images into png files.
73
73
  Converted png images stored into dirname/png/.
74
74
 
75
- You can view all converted png images with public/viewer.html.
75
+ To view converted images, "dirname/viewer.html" is created.
76
+ You can view all converted png images with "dirname/viewer.html" file in animation.
76
77
 
77
78
  This feature is supported only latest Ruby versions (2.2, and later).
78
79
 
80
+ #### Examaple
81
+
82
+ ```ruby
83
+ require 'gc_tracer'
84
+ GC::Tracer.start_objspace_recording("objspace_recorded_type_example", :type){
85
+ n = 1_000
86
+ m = 10_000
87
+
88
+ n.times{
89
+ ary = []
90
+ m.times{
91
+ ary << ''
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ This program takes all snapshot of type information at each GC events.
98
+
99
+ - :age (default) - take snapshots of age information (empty/young/old/shady)
100
+ - :type - take snapshots of type information (T_???)
101
+
102
+ You can see an [age example] (http://www.atdot.net/~ko1/gc_tracer/objspace_recorded_age_example/viewer.html) and
103
+ a [type example] (http://www.atdot.net/~ko1/gc_tracer/objspace_recorded_type_example/viewer.html).
104
+
79
105
  ## Contributing
80
106
 
81
107
  1. Fork it ( http://github.com/ko1/gc_tracer/fork )
@@ -1,7 +1,40 @@
1
- dir = ARGV.shift || 'records'
1
+ require 'erb'
2
+ require 'fileutils'
3
+
4
+ dir = ARGV.shift || 'objspace_records'
2
5
  Dir.mkdir("#{dir}/png") unless File.directory?("#{dir}/png")
6
+ first_gc_count = nil
7
+ last_gc_count = 0
3
8
 
4
9
  Dir.glob("#{dir}/ppm/*"){|file|
5
10
  cmd = "pnmtopng #{file} > #{dir}/png/#{File.basename(file)}.png"
6
11
  system(cmd)
12
+ if /(\d{8})\.\d/ =~ file
13
+ c = $1.to_i
14
+ first_gc_count = c if first_gc_count == nil || first_gc_count > c
15
+ last_gc_count = c if last_gc_count < c
16
+ end
17
+ }
18
+
19
+ color_description = {}
20
+ File.read("#{dir}/color_description.txt").each_line{|line|
21
+ desc, color = *line.chomp.split(/\t/)
22
+ color_description[desc] = color
23
+ }
24
+
25
+ color_description_js = color_description.map{|(k, v)|
26
+ " {desc: \"#{k}\", \t\"color\": \"#{v}\"}"
27
+ }.join(",\n")
28
+
29
+ html_file = "#{dir}/viewer.html"
30
+
31
+ open(html_file, 'w'){|f|
32
+ f.puts ERB.new(File.read(File.join(__dir__, "../lib/gc_tracer/viewer.html.erb"))).result(binding)
7
33
  }
34
+
35
+ unless File.exist?("#{dir}/jquery-2.1.0.min.js")
36
+ FileUtils.cp(File.join(__dir__, "../public/jquery-2.1.0.min.js"), "#{dir}/jquery-2.1.0.min.js")
37
+ end
38
+
39
+ puts "Success: see #{html_file}"
40
+
@@ -478,84 +478,127 @@ struct objspace_recording_data {
478
478
  int width, height;
479
479
  };
480
480
 
481
+ struct picker_description {
482
+ const char *name;
483
+ const int color;
484
+ };
485
+
481
486
  static void
482
487
  set_color(unsigned char *buff, int color)
483
488
  {
484
- buff[0] = (color >> 0) & 0xff;
489
+ buff[2] = (color >> 0) & 0xff;
485
490
  buff[1] = (color >> 8) & 0xff;
486
- buff[2] = (color >> 16) & 0xff;
487
- }
491
+ buff[0] = (color >> 16) & 0xff;
492
+ }
493
+
494
+ const int categorical_color10_colors[] = {
495
+ 0x1f77b4,
496
+ 0xff7f0e,
497
+ 0x2ca02c,
498
+ 0xd62728,
499
+ 0x9467bd,
500
+ 0x8c564b,
501
+ 0xe377c2,
502
+ 0x7f7f7f,
503
+ 0xbcbd22,
504
+ 0x17becf
505
+ };
488
506
 
489
507
  static int
490
508
  categorical_color10(int n)
491
509
  {
492
- const int colors[] = {
493
- 0x1f77b4,
494
- 0xff7f0e,
495
- 0x2ca02c,
496
- 0xd62728,
497
- 0x9467bd,
498
- 0x8c564b,
499
- 0xe377c2,
500
- 0x7f7f7f,
501
- 0xbcbd22,
502
- 0x17becf};
503
510
  assert(n < 10);
504
- return colors[n];
505
- }
511
+ return categorical_color10_colors[n];
512
+ }
513
+
514
+ const int categorical_color20_colors[] = {
515
+ 0x1f77b4,
516
+ 0xaec7e8,
517
+ 0xff7f0e,
518
+ 0xffbb78,
519
+ 0x2ca02c,
520
+ 0x98df8a,
521
+ 0xd62728,
522
+ 0xff9896,
523
+ 0x9467bd,
524
+ 0xc5b0d5,
525
+ 0x8c564b,
526
+ 0xc49c94,
527
+ 0xe377c2,
528
+ 0xf7b6d2,
529
+ 0x7f7f7f,
530
+ 0xc7c7c7,
531
+ 0xbcbd22,
532
+ 0xdbdb8d,
533
+ 0x17becf,
534
+ 0x9edae5,
535
+ };
506
536
 
507
537
  static int
508
538
  categorical_color20(int n)
509
539
  {
510
- const int colors[] = {
511
- 0x1f77b4,
512
- 0xaec7e8,
513
- 0xff7f0e,
514
- 0xffbb78,
515
- 0x2ca02c,
516
- 0x98df8a,
517
- 0xd62728,
518
- 0xff9896,
519
- 0x9467bd,
520
- 0xc5b0d5,
521
- 0x8c564b,
522
- 0xc49c94,
523
- 0xe377c2,
524
- 0xf7b6d2,
525
- 0x7f7f7f,
526
- 0xc7c7c7,
527
- 0xbcbd22,
528
- 0xdbdb8d,
529
- 0x17becf,
530
- 0x9edae5,
531
- };
532
540
  assert(n < 20);
533
- return colors[n];
541
+ return categorical_color20_colors[n];
534
542
  }
535
543
 
544
+ static struct picker_description object_age_picker_description[] = {
545
+ {"empty slot", 0},
546
+ {"old slot", 0x1f77b4},
547
+ {"young slot", 0xff7f0e},
548
+ {"shady slot", 0x2ca02c}
549
+ };
550
+
536
551
  static int
537
552
  object_age_picker(VALUE v) {
538
553
  if (RB_TYPE_P(v, T_NONE)) {
539
- return categorical_color10(0);
554
+ return 0;
540
555
  }
541
556
  else {
542
557
  if (OBJ_PROMOTED(v)) {
543
558
  /* old */
544
- return categorical_color10(1);
559
+ return categorical_color10(0);
545
560
  }
546
561
  else {
547
- /* young */
548
- return categorical_color10(2);
562
+ if (OBJ_WB_PROTECTED(v)) {
563
+ /* young */
564
+ return categorical_color10(1);
565
+ }
566
+ else {
567
+ return categorical_color10(2);
568
+ }
549
569
  }
550
570
  }
551
571
  }
552
572
 
573
+ static struct picker_description object_type_picker_description[] = {
574
+ {"RUBY_T_NONE", 0},
575
+ {"RUBY_T_OBJECT", 0x1f77b4},
576
+ {"RUBY_T_CLASS", 0xaec7e8},
577
+ {"RUBY_T_MODULE", 0xff7f0e},
578
+ {"RUBY_T_FLOAT", 0xffbb78},
579
+ {"RUBY_T_STRING", 0x2ca02c},
580
+ {"RUBY_T_REGEXP", 0x98df8a},
581
+ {"RUBY_T_ARRAY", 0xd62728},
582
+ {"RUBY_T_HASH", 0xff9896},
583
+ {"RUBY_T_STRUCT", 0x9467bd},
584
+ {"RUBY_T_BIGNUM", 0xc5b0d5},
585
+ {"RUBY_T_FILE", 0x8c564b},
586
+ {"RUBY_T_DATA", 0xc49c94},
587
+ {"RUBY_T_MATCH", 0xe377c2},
588
+ {"RUBY_T_COMPLEX", 0xf7b6d2},
589
+ {"RUBY_T_RATIONAL", 0x7f7f7f},
590
+ {"RUBY_T_NODE", 0xc7c7c7},
591
+ {"RUBY_T_ICLASS", 0xbcbd22},
592
+ {"RUBY_T_ZOMBIE", 0xdbdb8d},
593
+ };
594
+
553
595
  static int
554
596
  object_type_picker(VALUE v) {
555
597
  int type = BUILTIN_TYPE(v);
556
598
  int color = 0;
557
599
  switch (type) {
558
600
  case RUBY_T_NONE:
601
+ return 0;
559
602
  case RUBY_T_OBJECT:
560
603
  case RUBY_T_CLASS:
561
604
  case RUBY_T_MODULE:
@@ -571,12 +614,12 @@ object_type_picker(VALUE v) {
571
614
  case RUBY_T_MATCH:
572
615
  case RUBY_T_COMPLEX:
573
616
  case RUBY_T_RATIONAL: /* 0x0f */
574
- color = type;
617
+ color = type - 1;
575
618
  break;
576
619
  case RUBY_T_NODE:
577
620
  case RUBY_T_ICLASS:
578
621
  case RUBY_T_ZOMBIE:
579
- color = type - 11;
622
+ color = type - 12;
580
623
  break;
581
624
  default:
582
625
  rb_bug("object_type_picker: unreachable (type: %d)", type);
@@ -650,6 +693,27 @@ gc_tracer_stop_objspace_recording(VALUE self)
650
693
  return Qnil;
651
694
  }
652
695
 
696
+ static void
697
+ puts_color_description(VALUE dirname, struct picker_description desc[], int n)
698
+ {
699
+ char buff[0x200];
700
+ FILE *fp;
701
+ int i;
702
+
703
+ snprintf(buff, 0x200, "%s/color_description.txt", RSTRING_PTR(dirname));
704
+
705
+ if ((fp = fopen(buff, "w")) == NULL) {
706
+ rb_raise(rb_eRuntimeError, "puts_color_description: failed to open file");
707
+ }
708
+
709
+ for (i=0; i<n; i++) {
710
+ fprintf(fp, "%s\t#%06x\n", desc[i].name, desc[i].color);
711
+ }
712
+
713
+ fclose(fp);
714
+ }
715
+
716
+
653
717
  static VALUE
654
718
  gc_tracer_start_objspace_recording(int argc, VALUE *argv, VALUE self)
655
719
  {
@@ -679,9 +743,11 @@ gc_tracer_start_objspace_recording(int argc, VALUE *argv, VALUE self)
679
743
 
680
744
  if (picker_type == ID2SYM(rb_intern("age"))) {
681
745
  objspace_recorder_color_picker = object_age_picker;
746
+ puts_color_description(dirname, &object_age_picker_description[0], sizeof(object_age_picker_description) / sizeof(struct picker_description));
682
747
  }
683
748
  else if (picker_type == ID2SYM(rb_intern("type"))) {
684
749
  objspace_recorder_color_picker = object_type_picker;
750
+ puts_color_description(dirname, &object_type_picker_description[0], sizeof(object_type_picker_description) / sizeof(struct picker_description));
685
751
  }
686
752
  else {
687
753
  rb_raise(rb_eArgError, "unsupported picker type: %s", rb_id2name(SYM2ID(picker_type)));
data/gc_tracer.gemspec CHANGED
@@ -5,7 +5,7 @@ require 'gc_tracer/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "gc_tracer"
8
- spec.version = GcTracer::VERSION
8
+ spec.version = GC::Tracer::VERSION
9
9
  spec.authors = ["Koichi Sasada"]
10
10
  spec.email = ["ko1@atdot.net"]
11
11
  spec.summary = %q{gc_tracer gem adds GC::Tracer module.}
@@ -1,3 +1,3 @@
1
- module GcTracer
2
- VERSION = "0.1.1"
1
+ module GC::Tracer
2
+ VERSION = "0.1.2"
3
3
  end
@@ -0,0 +1,80 @@
1
+ <html>
2
+ <head>
3
+ <meta charset="utf-8">
4
+ <script src="./jquery-2.1.0.min.js"></script>
5
+
6
+ <script>
7
+
8
+ function startAnimation(){
9
+ var start = Number($("#start").val());
10
+ var end = Number($("#end").val());
11
+ var sleep_time = Number($("#wait").val());
12
+ var i = start, j = 0;
13
+
14
+ var timer_func = function(){
15
+ image_path = "./png/" + ("00000000"+i).slice(-8) + "." + j + ".ppm.png";
16
+ $("#view").attr({
17
+ src: image_path
18
+ });
19
+ $("#status").text(image_path);
20
+
21
+ if (j < 2) {
22
+ j += 1;
23
+ }
24
+ else {
25
+ if (i < end) {
26
+ i += 1;
27
+ j = 0;
28
+ }
29
+ else{
30
+ return false;
31
+ }
32
+ }
33
+ setTimeout(timer_func, sleep_time);
34
+ }
35
+
36
+ timer_func();
37
+ }
38
+
39
+ var color_description = [
40
+ <%= color_description_js %>
41
+ ];
42
+
43
+ function reloadConfig() {
44
+ $("#color_desc_table").remove();
45
+ $("#config").after("<table id='color_desc_table'></table>");
46
+
47
+ for (var i = 0; i < color_description.length; i++) {
48
+ $("#color_desc_table").before(
49
+ "<tr>" +
50
+ "<td style='background-color: " + color_description[i].color + "' hspace='1em' width='100px'>" +
51
+ "<td> " + color_description[i].desc + "</td>" +
52
+ "</tr>");
53
+ }
54
+ }
55
+
56
+ $(function(){
57
+ reloadConfig();
58
+ $("#submit").click(
59
+ function(){
60
+ startAnimation();
61
+ });
62
+ });
63
+
64
+ </script>
65
+ </head>
66
+ <body>
67
+ <div>
68
+ <div id='config'>
69
+ start: <input type='text' id='start' value='<%= first_gc_count %>' readonly>,
70
+ end: <input type='text' id='end' value='<%= last_gc_count %>' readonly>
71
+ </div>
72
+ </div>
73
+ <p>
74
+ <input type='submit' id='submit' value='start!'>
75
+ wait: <input type='text' id='wait' value='100'>
76
+ <span id='status'></span>
77
+ </p>
78
+ <img id='view'>
79
+ </body>
80
+ </html>
@@ -39,6 +39,8 @@ describe GC::Tracer do
39
39
  }
40
40
  }
41
41
  expect(Dir.glob("#{DIRNAME}/ppm/*.ppm").size).to be >= count * 3
42
+ rescue NoMethodError
43
+ pending "start_objspace_recording requires MRI >= 2.2"
42
44
  ensure
43
45
  FileUtils.rm_rf(DIRNAME) if File.directory?(DIRNAME)
44
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gc_tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Sasada
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-03 00:00:00.000000000 Z
11
+ date: 2014-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,8 +86,8 @@ files:
86
86
  - gc_tracer.gemspec
87
87
  - lib/gc_tracer.rb
88
88
  - lib/gc_tracer/version.rb
89
+ - lib/gc_tracer/viewer.html.erb
89
90
  - public/jquery-2.1.0.min.js
90
- - public/viewer.html
91
91
  - spec/gc_tracer_spec.rb
92
92
  - spec/spec_helper.rb
93
93
  homepage: https://github.com/ko1/gc_tracer
data/public/viewer.html DELETED
@@ -1,61 +0,0 @@
1
- <html>
2
- <head>
3
- <meta charset="utf-8">
4
- <script src="./jquery-2.1.0.min.js"></script>
5
-
6
- <script>
7
-
8
- function startAnimation(){
9
- var dir = $("#dir").val();
10
- var start = Number($("#start").val());
11
- var end = Number($("#end").val());
12
- var sleep_time = Number($("#wait").val());
13
- var i = start, j = 0;
14
-
15
- var timer_func = function(){
16
- image_path = dir + "/png/" + ("00000000"+i).slice(-8) + "." + j + ".ppm.png";
17
- $("#view").attr({
18
- src: image_path
19
- });
20
- $("#status").text(image_path);
21
-
22
- if (j < 2) {
23
- j += 1;
24
- }
25
- else {
26
- if (i < end) {
27
- i += 1;
28
- j = 0;
29
- }
30
- else{
31
- return false;
32
- }
33
- }
34
- setTimeout(timer_func, sleep_time);
35
- }
36
-
37
- timer_func();
38
- }
39
-
40
- $(function(){
41
- $("#submit").click(
42
- function(){
43
- startAnimation();
44
- });
45
- });
46
-
47
- </script>
48
- </head>
49
- <body>
50
- <p>
51
- dir: <input type='text' id='dir' value='test'>,
52
- start: <input type='text' id='start' value='5'>,
53
- end: <input type='text' id='end' value='100'>
54
- wait: <input type='text' id='wait' value='300'>,
55
- </p>
56
- <p>
57
- <input type='submit' id='submit' value='start!'><span id='status'></span>
58
- </p>
59
- <img id='view'>
60
- </body>
61
- </html>