majo 0.0.4 → 0.1.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
  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: []