gc_tracer 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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>