gc_tracer 1.1.0 → 1.2.0

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: b9ce36d7506d6380617767354fcf92f131fb8eb2
4
- data.tar.gz: cd6eeb8447b71f3e4ceafd623af6bf0e793c45a7
3
+ metadata.gz: 08efc028ba431a430f1e0d1ac444b74884e575b4
4
+ data.tar.gz: 04aa0ea80b8ce757cd32bce97a84644740c6a53c
5
5
  SHA512:
6
- metadata.gz: 28c17973fe087d97552e5b12d0e8e0a3b43e0910e2591ae9144d3e6225bdd008da490777939b7d2cd97582a2fbc7e907b18b4c2517869fa65cad7ffb36fc1b66
7
- data.tar.gz: b27a89753bf65de227143b1e5966e131e5c47cc595cd90332f0265fa6c6bd28a35febfc5306fa7b0615dd93ae6c8aeeaa9c61db034eadcdb85beeaa867c64808
6
+ metadata.gz: 299a15128bd5794000a3d631e5ca21132dbe954192f19c71c5b5a18f3332271646375d108be07b516ef7f803dab65fcd932e862e435e9a3ba7ddd3c0329e95af
7
+ data.tar.gz: b6132a320def13c6161a4dcc7e105c21f167c82e6ad03af303dd4f9f2f9a00b874c8e253bf3f864a0978737d2673e588f946087faae8307e368eca702208e3e6
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.2.0
data/README.md CHANGED
@@ -4,6 +4,8 @@ Trace Garbage Collector activities and output statistics information.
4
4
 
5
5
  This gem only supports MRI 2.1.0 and later.
6
6
 
7
+ [![Build Status](https://travis-ci.org/ko1/gc_tracer.svg)](https://travis-ci.org/ko1/gc_tracer)
8
+
7
9
  ## Installation
8
10
 
9
11
  Add this line to your application's Gemfile:
@@ -80,7 +82,7 @@ ensure
80
82
  end
81
83
  ```
82
84
 
83
- Default events are "start", "end_mark" and "end_sweep". You can specify
85
+ Default events are "start", "end_mark" and "end_sweep". You can specify
84
86
  what kind of information you want to collect.
85
87
 
86
88
  ```ruby
@@ -93,22 +95,48 @@ ensure
93
95
  end
94
96
  ```
95
97
 
96
- Above example means that no details information are not needed. Default
98
+ Above example means that no details information are not needed. Default
97
99
  setting is "gc_stat: true, gc_latest_gc_info: true, rusage: false".
98
100
 
99
- You can specify tick (time stamp) type with keyword parameter
100
- "tick_type". You can choose one of the tick type in :hw_counter, :time
101
+ You can specify tick (time stamp) type with keyword parameter
102
+ "tick_type". You can choose one of the tick type in :hw_counter, :time
101
103
  and :nano_time (if platform supports clock_gettime()).
102
104
 
103
105
  See lib/gc_tracer.rb for more details.
104
106
 
107
+ ### Custom fields
108
+
109
+ You can add custom fields.
110
+
111
+ ```ruby
112
+ GC::Tracer.start_logging(custom_fields: [:name1, :name2, ...]) do
113
+ # All fields are cleared by zero.
114
+
115
+ # You can increment values of each field.
116
+ GC::Tracer.custom_field_increment(:name1)
117
+ # It is equivalent to
118
+ # GC::Tracer.custom_field_set(:name1, GC::Tracer.custom_field_get(:name1))
119
+
120
+ # You can also decrement values
121
+ GC::Tracer.custom_field_decrement(:name1)
122
+
123
+ # Now, you can specify only Fixnum as field value.
124
+ GC::Tracer.custom_field_set(:name2, 123)
125
+
126
+ # You can specify an index instead of field name (faster than actual name)
127
+ GC::Tracer.custom_field_increment(0) # :name1
128
+ end
129
+ ```
130
+
131
+ Custom fields are printed as last columns.
132
+
105
133
  ### Custom events
106
134
 
107
- You can add custom events by your own. Calling
108
- `GC::Tracer.custom_event_logging(event_name)` in your program will puts
135
+ You can add custom events by your own. Calling
136
+ `GC::Tracer.custom_event_logging(event_name)` in your program will puts
109
137
  new statistics line into the logging file.
110
138
 
111
- For example, the following program insert 1000 custom event lines into
139
+ For example, the following program insert 1000 custom event lines into
112
140
  logging file (stderr for this type).
113
141
 
114
142
  ```ruby
@@ -120,7 +148,7 @@ GC::Tracer.start_logging(events: %i(start), gc_stat: false) do
120
148
  end
121
149
  ```
122
150
 
123
- This method is useful to trace where the GC events occur in your
151
+ This method is useful to trace where the GC events occur in your
124
152
  application.
125
153
 
126
154
 
@@ -66,6 +66,8 @@ tick(void)
66
66
  #define MAX_HOOKS 5
67
67
  #endif
68
68
 
69
+ #define MAX_CUSTOM_FIELDS 128
70
+
69
71
  static VALUE tracer_hooks[MAX_HOOKS];
70
72
  static VALUE tracer_acceptable_events[MAX_HOOKS];
71
73
 
@@ -77,12 +79,16 @@ struct gc_logging {
77
79
  int log_gc_stat;
78
80
  int log_gc_latest_gc_info;
79
81
  int log_rusage;
82
+ int log_custom_fields_count;
80
83
  } config;
81
84
 
82
85
  int enabled;
83
86
  VALUE enable_hooks[MAX_HOOKS]; /* Symbols */
84
87
  int enable_hooks_num; /* 0 to MAX_HOOKS */
85
88
 
89
+ ID custom_field_names[MAX_CUSTOM_FIELDS];
90
+ long custom_field_values[MAX_CUSTOM_FIELDS];
91
+
86
92
  FILE *out;
87
93
  const char *event;
88
94
 
@@ -138,6 +144,12 @@ out_sizet(FILE *out, size_t size)
138
144
  fprintf(out, "%lu\t", (unsigned long)size);
139
145
  }
140
146
 
147
+ static void
148
+ out_long(FILE *out, long l)
149
+ {
150
+ fprintf(out, "%ld\t", l);
151
+ }
152
+
141
153
  static double
142
154
  timeval2double(struct timeval *tv)
143
155
  {
@@ -303,6 +315,13 @@ out_stat(struct gc_logging *logging, const char *event)
303
315
  #if HAVE_GETRUSAGE
304
316
  if (logging->config.log_rusage) out_rusage(logging);
305
317
  #endif
318
+ if (logging->config.log_custom_fields_count > 0) {
319
+ int i;
320
+ for (i=0; i<logging->config.log_custom_fields_count; i++) {
321
+ out_long(logging->out, logging->custom_field_values[i]);
322
+ }
323
+ }
324
+
306
325
  out_terminate(logging->out);
307
326
  }
308
327
 
@@ -335,6 +354,12 @@ out_header(struct gc_logging *logging)
335
354
  out_header_each(logging, sym_rusage, sizeof(sym_rusage)/sizeof(VALUE));
336
355
  }
337
356
  #endif
357
+ if (logging->config.log_custom_fields_count > 0) {
358
+ int i;
359
+ for (i=0; i<logging->config.log_custom_fields_count; i++) {
360
+ out_str(logging->out, rb_id2name(logging->custom_field_names[i]));
361
+ }
362
+ }
338
363
  out_terminate(logging->out);
339
364
  }
340
365
 
@@ -540,6 +565,96 @@ gc_tracer_setup_logging_rusage(VALUE self, VALUE b)
540
565
  return self;
541
566
  }
542
567
 
568
+ static VALUE
569
+ gc_tracer_setup_logging_custom_fields(VALUE self, VALUE b)
570
+ {
571
+ struct gc_logging *logging = &trace_logging;
572
+
573
+ if (RTEST(b)) {
574
+ VALUE ary = rb_check_array_type(b);
575
+ int i;
576
+
577
+ logging->config.log_custom_fields_count = RARRAY_LEN(ary);
578
+
579
+ for (i=0; i<RARRAY_LEN(ary); i++) {
580
+ VALUE name = RARRAY_AREF(ary, i);
581
+ ID field_id = rb_to_id(name);
582
+
583
+ if (i >= MAX_CUSTOM_FIELDS) {
584
+ rb_raise(rb_eRuntimeError, "Number of custome fields exceeds %d", MAX_CUSTOM_FIELDS);
585
+ }
586
+
587
+ logging->custom_field_names[i] = field_id;
588
+ logging->custom_field_values[i] = 0;
589
+ }
590
+ }
591
+ else {
592
+ logging->config.log_custom_fields_count = 0;
593
+ }
594
+
595
+ return self;
596
+ }
597
+
598
+ static long *
599
+ custom_field_value_place(VALUE name)
600
+ {
601
+ struct gc_logging *logging = &trace_logging;
602
+ int index;
603
+
604
+ if (FIXNUM_P(name)) {
605
+ index = FIX2INT(name);
606
+ if (index >= logging->config.log_custom_fields_count) {
607
+ rb_raise(rb_eRuntimeError, "Only %d custom fields are available, but %d was specified",
608
+ logging->config.log_custom_fields_count, index);
609
+ }
610
+ }
611
+ else {
612
+ int i;
613
+ ID nid = rb_to_id(name);
614
+ for (i=0; i<logging->config.log_custom_fields_count; i++) {
615
+ if (nid == logging->custom_field_names[i]) {
616
+ index = i;
617
+ goto found;
618
+ }
619
+ }
620
+ rb_raise(rb_eRuntimeError, "Unkown custom fileds is specified.");
621
+ }
622
+ found:
623
+ return &logging->custom_field_values[index];
624
+ }
625
+
626
+ static VALUE
627
+ gc_tracer_custom_field_increment(VALUE self, VALUE name)
628
+ {
629
+ long *valp = custom_field_value_place(name);
630
+ (*valp)++;
631
+ return self;
632
+ }
633
+
634
+ static VALUE
635
+ gc_tracer_custom_field_decrement(VALUE self, VALUE name)
636
+ {
637
+ long *valp = custom_field_value_place(name);
638
+ (*valp)--;
639
+ return self;
640
+ }
641
+
642
+ static VALUE
643
+ gc_tracer_custom_field_get(VALUE self, VALUE name)
644
+ {
645
+ long *valp = custom_field_value_place(name);
646
+ return LONG2NUM(*valp);
647
+ }
648
+
649
+ static VALUE
650
+ gc_tracer_custom_field_set(VALUE self, VALUE name, VALUE val)
651
+ {
652
+ long *valp = custom_field_value_place(name);
653
+ long lval = NUM2LONG(val);
654
+ *valp = lval;
655
+ return val;
656
+ }
657
+
543
658
  static VALUE
544
659
  gc_tracer_start_logging(int argc, VALUE *argv, VALUE self)
545
660
  {
@@ -597,6 +712,13 @@ Init_gc_tracer_logging(VALUE mod)
597
712
  rb_define_module_function(mod, "setup_logging_gc_latest_gc_info=", gc_tracer_setup_logging_gc_latest_gc_info, 1);
598
713
  rb_define_module_function(mod, "setup_logging_rusage=", gc_tracer_setup_logging_rusage, 1);
599
714
 
715
+ /* custom fields */
716
+ rb_define_module_function(mod, "setup_looging_custom_fields=", gc_tracer_setup_logging_custom_fields, 1);
717
+ rb_define_module_function(mod, "custom_field_increment", gc_tracer_custom_field_increment, 1);
718
+ rb_define_module_function(mod, "custom_field_decrement", gc_tracer_custom_field_decrement, 1);
719
+ rb_define_module_function(mod, "custom_field_set", gc_tracer_custom_field_set, 2);
720
+ rb_define_module_function(mod, "custom_field_get", gc_tracer_custom_field_get, 1);
721
+
600
722
  /* custom event */
601
723
  rb_define_module_function(mod, "custom_event_logging", gc_tracer_custom_event_logging, 1);
602
724
 
data/lib/gc_tracer.rb CHANGED
@@ -12,7 +12,9 @@ module GC
12
12
  # collect information
13
13
  gc_stat: true,
14
14
  gc_latest_gc_info: true,
15
- rusage: false)
15
+ rusage: false,
16
+ custom_fields: nil
17
+ )
16
18
  # setup
17
19
  raise "do not specify two fienames" if filename && filename_opt
18
20
  setup_logging_out(filename_opt || filename)
@@ -22,6 +24,7 @@ module GC
22
24
  self.setup_logging_gc_latest_gc_info = gc_latest_gc_info
23
25
  self.setup_logging_rusage = rusage
24
26
  self.setup_logging_tick_type = tick_type
27
+ self.setup_looging_custom_fields = custom_fields
25
28
 
26
29
  if block_given?
27
30
  begin
@@ -1,3 +1,3 @@
1
1
  module GC::Tracer
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -28,6 +28,78 @@ describe GC::Tracer do
28
28
  it_behaves_like "logging_test"
29
29
  end
30
30
 
31
+ describe 'custom fields' do
32
+ describe 'manipulate values' do
33
+ around 'open' do |example|
34
+ Dir.mktmpdir('gc_tracer'){|dir|
35
+ logfile = "#{dir}/logging"
36
+ GC::Tracer.start_logging(logfile, custom_fields: %i(a b c)) do
37
+ example.run
38
+ end
39
+ }
40
+ end
41
+
42
+ it 'should raise error for unknown name or index' do
43
+ expect{GC::Tracer.custom_field_increment(:xyzzy)}.to raise_error RuntimeError
44
+ expect{GC::Tracer.custom_field_increment(42)}.to raise_error RuntimeError
45
+ end
46
+
47
+ it 'should count increments' do
48
+ GC::Tracer.custom_field_increment(:a)
49
+ GC::Tracer.custom_field_increment(:a)
50
+ GC::Tracer.custom_field_increment(:a)
51
+ GC::Tracer.custom_field_increment(0)
52
+ GC::Tracer.custom_field_increment(0)
53
+ GC::Tracer.custom_field_increment(0)
54
+
55
+ expect(GC::Tracer.custom_field_get(:a)).to be 6
56
+ expect(GC::Tracer.custom_field_get(0)).to be 6
57
+ end
58
+
59
+ it 'should count decments' do
60
+ GC::Tracer.custom_field_decrement(:b)
61
+ GC::Tracer.custom_field_decrement(:b)
62
+ GC::Tracer.custom_field_decrement(:b)
63
+ GC::Tracer.custom_field_decrement(1)
64
+ GC::Tracer.custom_field_decrement(1)
65
+ GC::Tracer.custom_field_decrement(1)
66
+
67
+ expect(GC::Tracer.custom_field_get(:b)).to be -6
68
+ expect(GC::Tracer.custom_field_get(1)).to be -6
69
+ end
70
+
71
+ it 'should set values' do
72
+ GC::Tracer.custom_field_set(:c, 42)
73
+ expect(GC::Tracer.custom_field_get(:c)).to be 42
74
+ GC::Tracer.custom_field_set(2, 43)
75
+ expect(GC::Tracer.custom_field_get(:c)).to be 43
76
+ end
77
+ end
78
+
79
+ describe 'output custome fields' do
80
+ it 'should output custome fields' do
81
+ Dir.mktmpdir('gc_tracer'){|dir|
82
+ logfile = "#{dir}/logging"
83
+ GC::Tracer.start_logging(logfile, custom_fields: %i(a b c)) do
84
+ GC::Tracer.custom_field_increment(:a)
85
+ GC::Tracer.custom_field_decrement(:b)
86
+ GC::Tracer.custom_event_logging("out")
87
+ end
88
+
89
+ expect(File.exist?(logfile)).to be_true
90
+ log = File.read(logfile)
91
+ expect(log.lines[0]).to match /a\tb\tc/
92
+ log.each_line{|line|
93
+ if /out/ =~ line
94
+ expect(line).to match /1\t-1\t0/
95
+ end
96
+ }
97
+ }
98
+ end
99
+ end
100
+ end
101
+
102
+
31
103
  =begin not supported now.
32
104
  shared_examples "objspace_recorder_test" do
33
105
  dirname = "gc_tracer_objspace_recorder_spec.#{$$}"
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: 1.1.0
4
+ version: 1.2.0
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-12-18 00:00:00.000000000 Z
11
+ date: 2015-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -76,6 +76,7 @@ extensions:
76
76
  extra_rdoc_files: []
77
77
  files:
78
78
  - ".gitignore"
79
+ - ".travis.yml"
79
80
  - Gemfile
80
81
  - LICENSE.txt
81
82
  - README.md
@@ -119,4 +120,3 @@ summary: gc_tracer gem adds GC::Tracer module.
119
120
  test_files:
120
121
  - spec/gc_tracer_spec.rb
121
122
  - spec/spec_helper.rb
122
- has_rdoc: