majo 0.0.4 → 0.1.0

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
  SHA256:
3
- metadata.gz: c68eebecd1591a5579a3c44135c7d29c7b46743c0f35c65f8ebd3b557bd78f4a
4
- data.tar.gz: 5742f4feabbead870b4becbeb8c40f5591eff79541f3f70dd4aef285c1de5f0d
3
+ metadata.gz: 84aa655c3585c95f2e639690246b2946114208ce08b979d00d46e6a93efef60c
4
+ data.tar.gz: 0073efd2fd643f97219ca17be43259960cfb514ab864cbb6f0b0f9378d3f7a9f
5
5
  SHA512:
6
- metadata.gz: e1e165da4e081ca6886db4631f1052bab452551b073784c90507da80d1f35672edc0a9b7ead753b32c5d1fc7884e8fe87778c76b38c0b8dbadbde417362902db
7
- data.tar.gz: 24cfe454a1f38b70f7c1b12d6f4bd3a1cf94384b9f18eabe10e27907e93c5b0e8417e53d405582086571e4cd649ca14d6d4cdd05e5e5b50794ff2994cc1f077f
6
+ metadata.gz: 7d0cb81a092b6c0db17c5db53d2a2404fc554c1545bf8ab7b6546679ba7bd9a64e603af30e2fe7d1d5f90fe0848aebba490918d5101a179b6ac309bf21e3b878
7
+ data.tar.gz: 630052b3e6c3558c7ce2628a17528518e3770188fca26b26ff1f51a69c6d3d14e339b03814a93173ed134e6565d4e6f1aa1a07249961a70360c8903949943889
data/ARCHITECTURE.md ADDED
@@ -0,0 +1,25 @@
1
+ # Architecture of Majo
2
+
3
+ Majo uses internal TracePoint hooks, `RUBY_INTERNAL_EVENT_NEWOBJ` and `RUBY_INTERNAL_EVENT_FREEOBJ`, to trace object allocation and free events.
4
+ We can use `ObjectSpace.trace_object_allocations_start` method in the Ruby-level, but this API is not suitable for Majo because it does not provide information about freed objects. Therefore, Majo uses these hooks in the C-level.
5
+
6
+ ## On allocation event
7
+
8
+ When an object is allocated, Majo records the object into a st table with the path, line number, and so on.
9
+
10
+ See `newobj_i` function in `majo.c`.
11
+
12
+ ## On free event
13
+
14
+ When an object is freed, Majo moves the allocation information to an array from the st table if it's a long-lived object.
15
+ It determines whether the object is long-lived by checking the GC count. If the object is not swept by a GC sweeping phase, it's a long-lived object.
16
+
17
+ See `freeobj_i` function in `majo.c`.
18
+
19
+ ## Output format
20
+
21
+ Majo provides three output formats: `color`, `monochrome`, and `csv`.
22
+
23
+ `color` and `monochrome` are for human-readable output. They provide overview information about long-lived objects.
24
+
25
+ `csv` is for machine-readable output. It provides the raw information. You can use this format to analyze the result with other tools.
data/README.md CHANGED
@@ -37,10 +37,10 @@ result.report
37
37
 
38
38
  You can pass the following options to `report` method.
39
39
 
40
- | Name | Description | Default | Type |
41
- | ----------- | ------------------------ | --------- | ------------------------------------------------------------------------ |
42
- | `out` | Output file or IO | `$stdout` | `IO`, `String` or an object having `to_path` method (such as `Pathname`) |
43
- | `formatter` | The format of the result | `:color` | `:color`, or `:csv` |
40
+ | Name | Description | Default | Type |
41
+ | ----------- | ------------------------ | ------------------------ | ------------------------------------------------------------------------ |
42
+ | `out` | Output file or IO | `$stdout` | `IO`, `String` or an object having `to_path` method (such as `Pathname`) |
43
+ | `formatter` | The format of the result | `:color` or `monochrome` | `:color`, `:monochrome`, or `:csv` |
44
44
 
45
45
  For example:
46
46
 
@@ -2,13 +2,12 @@
2
2
 
3
3
  static void majo_allocation_info_mark(void *ptr)
4
4
  {
5
- // TODO
6
5
  majo_allocation_info *info = (majo_allocation_info*)ptr;
6
+ rb_gc_mark(info->result);
7
7
  }
8
8
 
9
9
  static void majo_allocation_info_free(majo_allocation_info *info) {
10
- // TODO
11
- ruby_xfree(info);
10
+ free(info);
12
11
  }
13
12
 
14
13
  static size_t majo_allocation_info_memsize(const void *ptr) {
@@ -11,6 +11,8 @@ typedef struct {
11
11
  size_t alloc_generation;
12
12
  size_t free_generation;
13
13
  size_t memsize;
14
+
15
+ VALUE result;
14
16
  } majo_allocation_info;
15
17
 
16
18
  VALUE
data/ext/majo/majo.c CHANGED
@@ -39,7 +39,8 @@ internal_object_p(VALUE obj)
39
39
  static void
40
40
  newobj_i(VALUE tpval, void *data)
41
41
  {
42
- majo_result *arg = (majo_result *)data;
42
+ VALUE res = (VALUE)data;
43
+ majo_result *arg = majo_check_result(res);
43
44
 
44
45
  rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
45
46
  VALUE obj = rb_tracearg_object(tparg);
@@ -53,7 +54,6 @@ newobj_i(VALUE tpval, void *data)
53
54
  VALUE mid = rb_tracearg_method_id(tparg);
54
55
  VALUE klass = rb_tracearg_defined_class(tparg);
55
56
 
56
- // TODO: when the st already has an entry for the value
57
57
  majo_allocation_info *info = (majo_allocation_info *)malloc(sizeof(majo_allocation_info));
58
58
 
59
59
  const char *path_cstr = RTEST(path) ? majo_make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0;
@@ -66,6 +66,7 @@ newobj_i(VALUE tpval, void *data)
66
66
  const char *obj_class_path_cstr = RTEST(obj_class_path) ? majo_make_unique_str(arg->str_table, RSTRING_PTR(obj_class_path), RSTRING_LEN(obj_class_path)) : 0;
67
67
 
68
68
 
69
+ info->result = res;
69
70
  info->path = path_cstr;
70
71
  info->line = NUM2INT(line);
71
72
  info->mid = mid;
@@ -84,11 +85,9 @@ freeobj_i(VALUE tpval, void *data)
84
85
  st_data_t obj = (st_data_t)rb_tracearg_object(tparg);
85
86
  st_data_t v;
86
87
 
87
- // TODO refcount of the strings
88
88
  if (st_delete(arg->object_table, &obj, &v)) {
89
89
  majo_allocation_info *info = (majo_allocation_info *)v;
90
90
  size_t gc_count = rb_gc_count();
91
- // Reject it for majo
92
91
  if (info->alloc_generation < gc_count-1) {
93
92
  info->memsize = rb_obj_memsize_of((VALUE)obj);
94
93
  info->free_generation = gc_count;
@@ -110,7 +109,7 @@ start(VALUE self) {
110
109
  VALUE stack = rb_ivar_get(rb_mMajo, running_tracer_stack);
111
110
  rb_ary_push(stack, res);
112
111
 
113
- arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, arg);
112
+ arg->newobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, newobj_i, (void *)res);
114
113
  arg->freeobj_trace = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_FREEOBJ, freeobj_i, arg);
115
114
 
116
115
  rb_tracepoint_enable(arg->newobj_trace);
data/ext/majo/result.c CHANGED
@@ -7,14 +7,35 @@ static void majo_result_mark(void *ptr)
7
7
  rb_gc_mark(arg->freeobj_trace);
8
8
  }
9
9
 
10
+ static int
11
+ free_st_key(st_data_t key, st_data_t value, st_data_t data)
12
+ {
13
+ free((void *)key);
14
+ return ST_CONTINUE;
15
+ }
16
+
17
+ static int
18
+ free_st_value(st_data_t key, st_data_t value, st_data_t data)
19
+ {
20
+ free((void *)value);
21
+ return ST_CONTINUE;
22
+ }
23
+
10
24
  static void majo_result_free(majo_result *arg) {
11
- // TODO
12
- ruby_xfree(arg);
25
+ st_foreach(arg->object_table, free_st_value, 0);
26
+ st_free_table(arg->object_table);
27
+
28
+ st_foreach(arg->str_table, free_st_key, 0);
29
+ st_free_table(arg->str_table);
30
+
31
+ rb_darray_free(arg->olds);
32
+
33
+ free(arg);
13
34
  }
14
35
 
15
36
  static size_t majo_result_memsize(const void *ptr) {
16
- // TODO
17
- return sizeof(majo_result);
37
+ majo_result *res = (majo_result*)ptr;
38
+ return sizeof(majo_result) + st_memsize(res->object_table) + st_memsize(res->str_table) + rb_darray_capa(res->olds) * sizeof(majo_allocation_info);
18
39
  }
19
40
 
20
41
  static rb_data_type_t result_type = {
data/lib/majo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Majo
4
- VERSION = "0.0.4"
4
+ VERSION = "0.1.0"
5
5
  end
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: majo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masataka Pocke Kuwabara
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 2024-07-22 00:00:00.000000000 Z
11
+ date: 2024-07-25 00:00:00.000000000 Z
11
12
  dependencies: []
12
13
  description: A memory profiler focusing on long-lived objects.
13
14
  email:
@@ -19,6 +20,7 @@ extra_rdoc_files: []
19
20
  files:
20
21
  - ".rspec"
21
22
  - ".rubocop.yml"
23
+ - ARCHITECTURE.md
22
24
  - LICENSE
23
25
  - README.md
24
26
  - Rakefile
@@ -48,6 +50,7 @@ licenses:
48
50
  metadata:
49
51
  homepage_uri: https://github.com/pocke/majo
50
52
  source_code_uri: https://github.com/pocke/majo
53
+ post_install_message:
51
54
  rdoc_options: []
52
55
  require_paths:
53
56
  - lib
@@ -62,7 +65,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
65
  - !ruby/object:Gem::Version
63
66
  version: '0'
64
67
  requirements: []
65
- rubygems_version: 3.6.0.dev
68
+ rubygems_version: 3.5.11
69
+ signing_key:
66
70
  specification_version: 4
67
71
  summary: A memory profiler focusing on long-lived objects.
68
72
  test_files: []