heapfrag 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 34f0655dc516fcf2b46445069a24b10871962966
4
+ data.tar.gz: fe35bcbbcc206e612d765991edf93cc064f4accb
5
+ SHA512:
6
+ metadata.gz: f93c5c5986cd36f7ac8f5653c43dd0a3ecd5911ca7c7c17662fac68212101bcaecfe18ed1bf409169043d0bacde12ffc3275b63d7b56c02716274bde71045913
7
+ data.tar.gz: acb058f1591b5103f22c83e03fc91d7c578a1c9b68ced49a0a40829f83da19a2e7c8b5cf04a62604fdd030f50702dc8455fdaca8f8c95cbc945c62388cbfe153
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
14
+
15
+ # rspec failure tracking
16
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.4.10
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.4.10
7
+ before_install: gem install bundler -v 1.17.3
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in heapfrag.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Ivan Prisyazhnyy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # Heapfrag
2
+
3
+ This tool allows to measure a fragmentation of the Ruby VM heap.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'heapfrag'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install heapfrag
20
+
21
+ ## Usage
22
+
23
+ > require "heapfrag"
24
+ > Heapfrag::stat
25
+
26
+ {
27
+ :fragmented_pages=>146,
28
+ :pages_total=>154,
29
+ :pages_seen=>154,
30
+ :pages_with_alive=>154,
31
+ :pages_with_dead=>146,
32
+ :pages_free=>0,
33
+ :pages_full=>8,
34
+ :objs_alive=>47812,
35
+ :objs_dead=>14961,
36
+ 0% 50% 95% 99% 99.9% 100%
37
+ :heap_pages_fill_cdf=>[0, 22, 116, 133, 142, 154]
38
+ }
39
+
40
+ ## Quick start
41
+
42
+ $ rake compile && echo 'require "heapfrag"; Heapfrag::stat' | irb
43
+ install -c tmp/x86_64-linux/heapfrag/2.4.10/heapfrag.so lib/heapfrag/heapfrag.so
44
+ cp tmp/x86_64-linux/heapfrag/2.4.10/heapfrag.so tmp/x86_64-linux/stage/lib/heapfrag/heapfrag.so
45
+ Switch to inspect mode.
46
+ require "heapfrag"; Heapfrag::stat
47
+ {:fragmented_pages=>146, :pages_total=>154, :pages_seen=>154, :pages_with_alive=>154, :pages_with_dead=>146, :pages_free=>0, :pages_full=>8, :objs_alive=>47812, :objs_dead=>14961, :heap_pages_fill_cdf=>[0, 22, 116, 133, 142, 154]}
48
+
49
+ ## Development
50
+
51
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
52
+
53
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+
55
+ ## Contributing
56
+
57
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sitano/heapfrag. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
58
+
59
+ ## License
60
+
61
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require "rake/extensiontask"
7
+
8
+ task :build => :compile
9
+
10
+ Rake::ExtensionTask.new("heapfrag") do |ext|
11
+ ext.lib_dir = "lib/heapfrag"
12
+ end
13
+
14
+ task :default => [:clobber, :compile, :spec]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "heapfrag"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("heapfrag/heapfrag")
@@ -0,0 +1,133 @@
1
+ #include "heapfrag.h"
2
+
3
+ // #include <stdio.h>
4
+
5
+ VALUE rb_mHeapfrag;
6
+
7
+ VALUE sym_fragmented_pages;
8
+ VALUE sym_pages_total;
9
+ VALUE sym_pages_seen;
10
+ VALUE sym_pages_walive;
11
+ VALUE sym_pages_wdead;
12
+ VALUE sym_pages_free;
13
+ VALUE sym_pages_full;
14
+ VALUE sym_alive_objs;
15
+ VALUE sym_dead_objs;
16
+ VALUE sym_heap_allocated_pages;
17
+ VALUE sym_pages_fill_cdf;
18
+
19
+ static size_t cdf_levels[] = {
20
+ 1, // 0
21
+ HEAP_PAGE_OBJ_LIMIT * 50 / 100, // 50%
22
+ HEAP_PAGE_OBJ_LIMIT * 95 / 100, // 95%
23
+ HEAP_PAGE_OBJ_LIMIT * 99 / 100, // 99%
24
+ HEAP_PAGE_OBJ_LIMIT * 999 / 1000, // 99.9%
25
+ HEAP_PAGE_OBJ_LIMIT // inf+
26
+ };
27
+
28
+ struct heap_info {
29
+ size_t pages_seen;
30
+ size_t pages_walive;
31
+ size_t pages_wdead;
32
+ size_t pages_free;
33
+ size_t pages_full;
34
+ size_t alive_objs;
35
+ size_t dead_objs;
36
+ size_t cdf[sizeof(cdf_levels) / sizeof(size_t)];
37
+ };
38
+
39
+ static void
40
+ insert_cdf(struct heap_info *info, size_t val)
41
+ {
42
+ static size_t size = sizeof(cdf_levels) / sizeof(size_t);
43
+
44
+ for (size_t i = 0; i < size; i ++) {
45
+ if (val < cdf_levels[i]) {
46
+ info->cdf[i] ++;
47
+ }
48
+ }
49
+
50
+ if (val >= cdf_levels[size - 1]) {
51
+ info->cdf[size - 1] ++;
52
+ }
53
+ }
54
+
55
+ static int
56
+ count_objects_i(void *vstart, void *vend, size_t stride, void *data)
57
+ {
58
+ struct heap_info *info = (struct heap_info *)data;
59
+ VALUE v = (VALUE)vstart;
60
+ size_t alive = 0;
61
+ size_t dead = 0;
62
+
63
+ for (; v != (VALUE)vend; v += stride) {
64
+ if (RBASIC(v)->flags) {
65
+ alive ++;
66
+ } else {
67
+ dead ++;
68
+ }
69
+ }
70
+
71
+ info->pages_seen ++;
72
+ info->alive_objs += alive;
73
+ info->dead_objs += dead;
74
+ if (alive) {
75
+ info->pages_walive ++;
76
+ } else {
77
+ info->pages_free ++;
78
+ }
79
+ if (dead) {
80
+ info->pages_wdead ++;
81
+ } else {
82
+ info->pages_full ++;
83
+ }
84
+
85
+ insert_cdf(info, alive);
86
+
87
+ // printf("%ld / %ld: %p - %p = (%ld)\n", alive, dead, vstart, vend, (vend-vstart)/40);
88
+
89
+ return 0;
90
+ }
91
+
92
+ static VALUE
93
+ heapfrag_stat(VALUE mod)
94
+ {
95
+ struct heap_info info = {};
96
+ VALUE rv = rb_hash_new();
97
+ size_t total_pages = rb_gc_stat(sym_heap_allocated_pages);
98
+
99
+ rb_objspace_each_objects(count_objects_i, &info);
100
+ rb_hash_aset(rv, sym_fragmented_pages, INT2FIX(total_pages - info.pages_full - info.pages_free));
101
+ rb_hash_aset(rv, sym_pages_total, INT2FIX(total_pages));
102
+ rb_hash_aset(rv, sym_pages_seen, INT2FIX(info.pages_seen));
103
+ rb_hash_aset(rv, sym_pages_walive, INT2FIX(info.pages_walive));
104
+ rb_hash_aset(rv, sym_pages_wdead, INT2FIX(info.pages_wdead));
105
+ rb_hash_aset(rv, sym_pages_free, INT2FIX(info.pages_free));
106
+ rb_hash_aset(rv, sym_pages_full, INT2FIX(info.pages_full));
107
+ rb_hash_aset(rv, sym_alive_objs, INT2FIX(info.alive_objs));
108
+ rb_hash_aset(rv, sym_dead_objs, INT2FIX(info.dead_objs));
109
+ rb_hash_aset(rv, sym_pages_fill_cdf,
110
+ rb_ary_new_from_args(6, INT2FIX(info.cdf[0]), INT2FIX(info.cdf[1]), INT2FIX(info.cdf[2]),
111
+ INT2FIX(info.cdf[3]), INT2FIX(info.cdf[4]), INT2FIX(info.cdf[5])));
112
+
113
+ return rv;
114
+ }
115
+
116
+ void
117
+ Init_heapfrag(void)
118
+ {
119
+ rb_mHeapfrag = rb_define_module("Heapfrag");
120
+ rb_define_singleton_method(rb_mHeapfrag, "stat", heapfrag_stat, 0);
121
+
122
+ sym_fragmented_pages = ID2SYM(rb_intern("fragmented_pages"));
123
+ sym_pages_total = ID2SYM(rb_intern("pages_total"));
124
+ sym_pages_seen = ID2SYM(rb_intern("pages_seen"));
125
+ sym_pages_walive = ID2SYM(rb_intern("pages_with_alive"));
126
+ sym_pages_wdead = ID2SYM(rb_intern("pages_with_dead"));
127
+ sym_pages_free = ID2SYM(rb_intern("pages_free"));
128
+ sym_pages_full = ID2SYM(rb_intern("pages_full"));
129
+ sym_alive_objs = ID2SYM(rb_intern("objs_alive"));
130
+ sym_dead_objs = ID2SYM(rb_intern("objs_dead"));
131
+ sym_heap_allocated_pages = ID2SYM(rb_intern("heap_allocated_pages"));
132
+ sym_pages_fill_cdf = ID2SYM(rb_intern("heap_pages_fill_cdf"));
133
+ }
@@ -0,0 +1,27 @@
1
+ #ifndef HEAPFRAG_H
2
+ #define HEAPFRAG_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ void rb_objspace_each_objects(
7
+ int (*callback)(void *start, void *end, size_t stride, void *data),
8
+ void *data);
9
+
10
+ size_t rb_gc_stat(VALUE hash_or_sym);
11
+
12
+ #ifndef HEAP_PAGE_ALIGN_LOG
13
+ /* default tiny heap size: 16KB */
14
+ #define HEAP_PAGE_ALIGN_LOG 14
15
+ #endif
16
+
17
+ enum {
18
+ HEAP_PAGE_ALIGN = (1UL << HEAP_PAGE_ALIGN_LOG),
19
+ HEAP_PAGE_ALIGN_MASK = (~(~0UL << HEAP_PAGE_ALIGN_LOG)),
20
+ REQUIRED_SIZE_BY_MALLOC = (sizeof(size_t) * 5),
21
+ HEAP_PAGE_SIZE = (HEAP_PAGE_ALIGN - REQUIRED_SIZE_BY_MALLOC),
22
+ HEAP_PAGE_HEADER_SIZE = sizeof(void *),
23
+ RVALUE_SIZE = 40,
24
+ HEAP_PAGE_OBJ_LIMIT = (unsigned int)((HEAP_PAGE_SIZE - HEAP_PAGE_HEADER_SIZE)/RVALUE_SIZE)
25
+ };
26
+
27
+ #endif
data/heapfrag.gemspec ADDED
@@ -0,0 +1,44 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "heapfrag/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "heapfrag"
8
+ spec.version = Heapfrag::VERSION
9
+ spec.authors = ["Ivan Prisyazhnyy"]
10
+ spec.email = ["john.koepi@gmail.com"]
11
+
12
+ spec.summary = "This tool allows to measure a fragmentation of the Ruby VM heap."
13
+ # spec.description = %q{Write a longer description or delete this line.}
14
+ spec.homepage = "https://github.com/sitano/heapfrag"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "Set to 'http://mygemserver.com'"
21
+
22
+ spec.metadata["homepage_uri"] = spec.homepage
23
+ spec.metadata["source_code_uri"] = "https://github.com/sitano/heapfrag"
24
+ # spec.metadata["changelog_uri"] = "Put your gem's CHANGELOG.md URL here."
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+ spec.extensions = ["ext/heapfrag/extconf.rb"]
39
+
40
+ spec.add_development_dependency "bundler", "~> 1.17"
41
+ spec.add_development_dependency "rake", "~> 10.0"
42
+ spec.add_development_dependency "rake-compiler"
43
+ spec.add_development_dependency "rspec", "~> 3.0"
44
+ end
@@ -0,0 +1,3 @@
1
+ module Heapfrag
2
+ VERSION = "0.1.0"
3
+ end
data/lib/heapfrag.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "heapfrag/version"
2
+ require "heapfrag/heapfrag"
3
+
4
+ module Heapfrag
5
+ class Error < StandardError; end
6
+ # Your code goes here...
7
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: heapfrag
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ivan Prisyazhnyy
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description:
70
+ email:
71
+ - john.koepi@gmail.com
72
+ executables: []
73
+ extensions:
74
+ - ext/heapfrag/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".tool-versions"
80
+ - ".travis.yml"
81
+ - Gemfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - bin/console
86
+ - bin/setup
87
+ - ext/heapfrag/extconf.rb
88
+ - ext/heapfrag/heapfrag.c
89
+ - ext/heapfrag/heapfrag.h
90
+ - heapfrag.gemspec
91
+ - lib/heapfrag.rb
92
+ - lib/heapfrag/version.rb
93
+ homepage: https://github.com/sitano/heapfrag
94
+ licenses:
95
+ - MIT
96
+ metadata:
97
+ homepage_uri: https://github.com/sitano/heapfrag
98
+ source_code_uri: https://github.com/sitano/heapfrag
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.6.14.4
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: This tool allows to measure a fragmentation of the Ruby VM heap.
119
+ test_files: []