benchmark-malloc 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 +7 -0
 - data/CHANGELOG.md +7 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +67 -0
 - data/Rakefile +8 -0
 - data/benchmark-malloc.gemspec +34 -0
 - data/lib/benchmark-malloc.rb +1 -0
 - data/lib/benchmark/malloc.rb +130 -0
 - data/lib/benchmark/malloc/allocation.rb +49 -0
 - data/lib/benchmark/malloc/allocation_result.rb +24 -0
 - data/lib/benchmark/malloc/allocation_set.rb +49 -0
 - data/lib/benchmark/malloc/version.rb +7 -0
 - data/spec/spec_helper.rb +31 -0
 - data/spec/unit/allocation/new_spec.rb +24 -0
 - data/spec/unit/allocation_set/new_spec.rb +46 -0
 - data/spec/unit/run_spec.rb +78 -0
 - data/tasks/console.rake +11 -0
 - data/tasks/coverage.rake +11 -0
 - data/tasks/spec.rake +34 -0
 - metadata +106 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 95f4aeccd4fe1f05278d14d87023639aad34522818a4189d7b72479351ce2565
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: faf9e95804733e6de3a77e32c7f6965e27358bc157810857de5da55c074fb7df
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 1ada0b8d9a8b86ee935ec5ca3acb871fff6b8a110b154fdde435f793271e42a95907383303d8151856ce252c91b1ce605f14cf7c3802d0351967bfc935e6812f
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 4b35be840c0e8a63730a5627e36efb53e19ba4fdae5d106544d37a8bf325bf6f6c35a90d3aafedf2ce0f84fb117e45a18b24ddfd0d1cd0842dc93a35fec81a54
         
     | 
    
        data/CHANGELOG.md
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2019 Piotr Murach
         
     | 
| 
      
 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,67 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Benchmark::Malloc
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            [][gem]
         
     | 
| 
      
 4 
     | 
    
         
            +
            [][travis]
         
     | 
| 
      
 5 
     | 
    
         
            +
            [][appveyor]
         
     | 
| 
      
 6 
     | 
    
         
            +
            [][codeclimate]
         
     | 
| 
      
 7 
     | 
    
         
            +
            [][coverage]
         
     | 
| 
      
 8 
     | 
    
         
            +
            [][inchpages]
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            [gem]: http://badge.fury.io/rb/benchmark-malloc
         
     | 
| 
      
 11 
     | 
    
         
            +
            [travis]: http://travis-ci.org/piotrmurach/benchmark-malloc
         
     | 
| 
      
 12 
     | 
    
         
            +
            [appveyor]: https://ci.appveyor.com/project/piotrmurach/benchmark-malloc
         
     | 
| 
      
 13 
     | 
    
         
            +
            [codeclimate]: https://codeclimate.com/github/piotrmurach/benchmark-malloc/maintainability
         
     | 
| 
      
 14 
     | 
    
         
            +
            [coverage]: https://coveralls.io/github/piotrmurach/benchmark-malloc?branch=master
         
     | 
| 
      
 15 
     | 
    
         
            +
            [inchpages]: http://inch-ci.org/github/piotrmurach/benchmark-malloc
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            > Trace memory allocations and collect stats.
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 24 
     | 
    
         
            +
            gem 'benchmark-malloc'
         
     | 
| 
      
 25 
     | 
    
         
            +
            ```
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                $ gem install benchmark-malloc
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 38 
     | 
    
         
            +
            benc_malloc = Benchmark::Malloc.new
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            stats = bench_malloc.run { %w[foo bar baz].sort[1] }
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            stats.allocated.total_objects # => 3
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            stats.allocated.total_memory # => 120
         
     | 
| 
      
 45 
     | 
    
         
            +
            ```
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            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.
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            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).
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/benchmark-malloc. 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.
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            ## Code of Conduct
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Everyone interacting in the Benchmark::Malloc project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/benchmark-malloc/blob/master/CODE_OF_CONDUCT.md).
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            ## Copyright
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            Copyright (c) 2019 Piotr Murach. See LICENSE for further details.
         
     | 
    
        data/Rakefile
    ADDED
    
    
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            lib = File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require "benchmark/malloc/version"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name          = "benchmark-malloc"
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version       = Benchmark::Malloc::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors       = ["Piotr Murach"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email         = ["me@piotrmurach.com"]
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary       = %q{Trace memory allocations and collect stats.}
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description   = %q{Trace memory allocations and collect stats.}
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.homepage      = "https://github.com/piotrmurach/benchmark-malloc"
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.license       = "MIT"
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              if spec.respond_to?(:metadata)
         
     | 
| 
      
 17 
     | 
    
         
            +
                spec.metadata["homepage_uri"] = spec.homepage
         
     | 
| 
      
 18 
     | 
    
         
            +
                spec.metadata["source_code_uri"] = "https://github.com/piotrmurach/benchmark-malloc"
         
     | 
| 
      
 19 
     | 
    
         
            +
                spec.metadata["changelog_uri"] = "https://github.com/piotrmurach/benchmark-malloc/CHANGELOG.md"
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              spec.files         = Dir['{lib,spec}/**/*.rb']
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.files        += Dir['tasks/*', 'benchmark-malloc.gemspec']
         
     | 
| 
      
 24 
     | 
    
         
            +
              spec.files        += Dir['README.md', 'CHANGELOG.md', 'LICENSE.txt', 'Rakefile']
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.bindir        = "exe"
         
     | 
| 
      
 26 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         
     | 
| 
      
 27 
     | 
    
         
            +
              spec.require_paths = ["lib"]
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              spec.required_ruby_version = '>= 2.1.0'
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              spec.add_development_dependency "bundler", ">= 1.17"
         
     | 
| 
      
 32 
     | 
    
         
            +
              spec.add_development_dependency "rake"
         
     | 
| 
      
 33 
     | 
    
         
            +
              spec.add_development_dependency "rspec", ">= 3.0"
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'benchmark/malloc'
         
     | 
| 
         @@ -0,0 +1,130 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'objspace'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'malloc/allocation'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'malloc/allocation_set'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'malloc/allocation_result'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative 'malloc/version'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            module Benchmark
         
     | 
| 
      
 11 
     | 
    
         
            +
              class Malloc
         
     | 
| 
      
 12 
     | 
    
         
            +
                class Error < StandardError; end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                attr_reader :generation
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                # It runs Ruby VM before tracing object allocations
         
     | 
| 
      
 17 
     | 
    
         
            +
                #
         
     | 
| 
      
 18 
     | 
    
         
            +
                # @api public
         
     | 
| 
      
 19 
     | 
    
         
            +
                attr_reader :warmup
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def self.run(&work)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Malloc.new.run(&work)
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def initialize(warmup: 0)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @warmup = warmup
         
     | 
| 
      
 27 
     | 
    
         
            +
                  @running = false
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @alloc_path = ::File.join(__FILE__[0...-3], 'allocation.rb')
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 32 
     | 
    
         
            +
                def check_running
         
     | 
| 
      
 33 
     | 
    
         
            +
                  unless @running
         
     | 
| 
      
 34 
     | 
    
         
            +
                    raise Error, "not started yet"
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                # Start allocation tracing
         
     | 
| 
      
 39 
     | 
    
         
            +
                #
         
     | 
| 
      
 40 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 41 
     | 
    
         
            +
                #   malloc = Malloc.new
         
     | 
| 
      
 42 
     | 
    
         
            +
                #   malloc.start
         
     | 
| 
      
 43 
     | 
    
         
            +
                #
         
     | 
| 
      
 44 
     | 
    
         
            +
                # @api public
         
     | 
| 
      
 45 
     | 
    
         
            +
                def start
         
     | 
| 
      
 46 
     | 
    
         
            +
                  if @running
         
     | 
| 
      
 47 
     | 
    
         
            +
                    raise Error, "already running"
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  GC.start
         
     | 
| 
      
 51 
     | 
    
         
            +
                  GC.disable
         
     | 
| 
      
 52 
     | 
    
         
            +
                  @generation = GC.count
         
     | 
| 
      
 53 
     | 
    
         
            +
                  @running = true
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @existing_ids = []
         
     | 
| 
      
 55 
     | 
    
         
            +
                  ObjectSpace.each_object do |object|
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @existing_ids << object.__id__
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  ObjectSpace.trace_object_allocations_start
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                # Stop allocation tracing if currently running
         
     | 
| 
      
 62 
     | 
    
         
            +
                #
         
     | 
| 
      
 63 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 64 
     | 
    
         
            +
                #   Malloc.stop
         
     | 
| 
      
 65 
     | 
    
         
            +
                #
         
     | 
| 
      
 66 
     | 
    
         
            +
                # @api public
         
     | 
| 
      
 67 
     | 
    
         
            +
                def stop
         
     | 
| 
      
 68 
     | 
    
         
            +
                  check_running
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  ObjectSpace.trace_object_allocations_stop
         
     | 
| 
      
 71 
     | 
    
         
            +
                  allocated = collect_allocations
         
     | 
| 
      
 72 
     | 
    
         
            +
                  retained  = []
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @running  = false
         
     | 
| 
      
 74 
     | 
    
         
            +
                  GC.enable
         
     | 
| 
      
 75 
     | 
    
         
            +
                  GC.start
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  ObjectSpace.each_object do |object|
         
     | 
| 
      
 78 
     | 
    
         
            +
                    next unless ObjectSpace.allocation_generation(object) == generation
         
     | 
| 
      
 79 
     | 
    
         
            +
                    next unless allocated.key?(object.__id__)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    retained << allocated[object.__id__]
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  ObjectSpace.trace_object_allocations_clear
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  AllocationResult.new(AllocationSet.new(allocated.values),
         
     | 
| 
      
 86 
     | 
    
         
            +
                                        AllocationSet.new(retained))
         
     | 
| 
      
 87 
     | 
    
         
            +
                end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                # Gather allocation stats of Ruby code inside of the block
         
     | 
| 
      
 90 
     | 
    
         
            +
                #
         
     | 
| 
      
 91 
     | 
    
         
            +
                # @example
         
     | 
| 
      
 92 
     | 
    
         
            +
                #   malloc = Malloc.new
         
     | 
| 
      
 93 
     | 
    
         
            +
                #   malloc.run { ... }
         
     | 
| 
      
 94 
     | 
    
         
            +
                #
         
     | 
| 
      
 95 
     | 
    
         
            +
                # @return [Malloc::Result]
         
     | 
| 
      
 96 
     | 
    
         
            +
                #
         
     | 
| 
      
 97 
     | 
    
         
            +
                # @api public
         
     | 
| 
      
 98 
     | 
    
         
            +
                def run(&work)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  start
         
     | 
| 
      
 100 
     | 
    
         
            +
                  warmup.times { yield }
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 103 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 104 
     | 
    
         
            +
                  rescue Exception
         
     | 
| 
      
 105 
     | 
    
         
            +
                    ObjectSpace.trace_object_allocations_stop
         
     | 
| 
      
 106 
     | 
    
         
            +
                    GC.enable
         
     | 
| 
      
 107 
     | 
    
         
            +
                    raise
         
     | 
| 
      
 108 
     | 
    
         
            +
                  else
         
     | 
| 
      
 109 
     | 
    
         
            +
                    stop
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                private
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 116 
     | 
    
         
            +
                def collect_allocations
         
     | 
| 
      
 117 
     | 
    
         
            +
                  allocations = {}
         
     | 
| 
      
 118 
     | 
    
         
            +
                  ObjectSpace.each_object do |object|
         
     | 
| 
      
 119 
     | 
    
         
            +
                    next unless ObjectSpace.allocation_generation(object) == generation
         
     | 
| 
      
 120 
     | 
    
         
            +
                    next if ObjectSpace.allocation_sourcefile(object).nil?
         
     | 
| 
      
 121 
     | 
    
         
            +
                    next if ObjectSpace.allocation_sourcefile(object) == __FILE__
         
     | 
| 
      
 122 
     | 
    
         
            +
                    next if ObjectSpace.allocation_sourcefile(object) == @alloc_path
         
     | 
| 
      
 123 
     | 
    
         
            +
                    next if @existing_ids.include?(object.__id__)
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    allocations[object.__id__] = Allocation.new(object)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
                  allocations
         
     | 
| 
      
 128 
     | 
    
         
            +
                end
         
     | 
| 
      
 129 
     | 
    
         
            +
              end # Malloc
         
     | 
| 
      
 130 
     | 
    
         
            +
            end # Benchmark
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'objspace'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Benchmark
         
     | 
| 
      
 6 
     | 
    
         
            +
              class Malloc
         
     | 
| 
      
 7 
     | 
    
         
            +
                class Allocation
         
     | 
| 
      
 8 
     | 
    
         
            +
                  include Comparable
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # The allocated object
         
     | 
| 
      
 11 
     | 
    
         
            +
                  attr_reader :object
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  # The allocated object memory size
         
     | 
| 
      
 14 
     | 
    
         
            +
                  attr_reader :memsize
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  attr_reader :class_path
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  attr_reader :source_file
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  attr_reader :source_line
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  attr_reader :method_id
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def initialize(object)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @object      = object
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @memsize     = ObjectSpace.memsize_of(object)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @class_path  = ObjectSpace.allocation_class_path(object)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @source_file = ObjectSpace.allocation_sourcefile(object)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @source_line = ObjectSpace.allocation_sourceline(object)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @method_id   = ObjectSpace.allocation_method_id(object)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def extract(*attributes)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    attributes.map do |attr|
         
     | 
| 
      
 35 
     | 
    
         
            +
                      if @object.respond_to?(attr)
         
     | 
| 
      
 36 
     | 
    
         
            +
                        @object.public_send(attr)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      else
         
     | 
| 
      
 38 
     | 
    
         
            +
                        public_send(attr)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def <=>(other)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @object <=> other.object &&
         
     | 
| 
      
 45 
     | 
    
         
            +
                      @memsize <=> other.memsize
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end # Allocation
         
     | 
| 
      
 48 
     | 
    
         
            +
              end # Malloc
         
     | 
| 
      
 49 
     | 
    
         
            +
            end # Benchmark
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Benchmark
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Malloc
         
     | 
| 
      
 5 
     | 
    
         
            +
                class AllocationResult
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :allocated
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :retained
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(allocated, retained)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @allocated = allocated
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @retained = retained
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def total_allocated_objects
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @allocated.total_objects
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def total_retained_objects
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @retained.total_objects
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end # AllocationResult
         
     | 
| 
      
 23 
     | 
    
         
            +
              end # Malloc
         
     | 
| 
      
 24 
     | 
    
         
            +
            end # Benchmark
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Benchmark
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Malloc
         
     | 
| 
      
 5 
     | 
    
         
            +
                class AllocationSet
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include Enumerable
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :allocations
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(allocations)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @allocations = allocations
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def each(&block)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    return to_enum(:each) unless block
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @allocations.each(&block)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def total_objects
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @allocations.size
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def total_memory
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @allocations.reduce(0) { |acc, alloc| acc + alloc.memsize }
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 30 
     | 
    
         
            +
                  def count_objects
         
     | 
| 
      
 31 
     | 
    
         
            +
                    @allocations.
         
     | 
| 
      
 32 
     | 
    
         
            +
                      map { |alloc| alloc.object.class }.
         
     | 
| 
      
 33 
     | 
    
         
            +
                      each_with_object(Hash.new(0)) { |name, h| h[name] += 1 }
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  # @api public
         
     | 
| 
      
 37 
     | 
    
         
            +
                  def count_memory
         
     | 
| 
      
 38 
     | 
    
         
            +
                    @allocations.
         
     | 
| 
      
 39 
     | 
    
         
            +
                      map { |alloc| [alloc.object.class, alloc.memsize] }.
         
     | 
| 
      
 40 
     | 
    
         
            +
                      each_with_object(Hash.new(0)) { |(name, mem), h| h[name] += mem }
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  def filter(*class_names)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @allocations.
         
     | 
| 
      
 45 
     | 
    
         
            +
                      select { |alloc| class_names.include?(alloc.object.class) }
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end # AllocationSet
         
     | 
| 
      
 48 
     | 
    
         
            +
              end # Malloc
         
     | 
| 
      
 49 
     | 
    
         
            +
            end # Benchmark
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            if ENV['COVERAGE'] || ENV['TRAVIS']
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'simplecov'
         
     | 
| 
      
 5 
     | 
    
         
            +
              require 'coveralls'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
         
     | 
| 
      
 8 
     | 
    
         
            +
                SimpleCov::Formatter::HTMLFormatter,
         
     | 
| 
      
 9 
     | 
    
         
            +
                Coveralls::SimpleCov::Formatter
         
     | 
| 
      
 10 
     | 
    
         
            +
              ]
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              SimpleCov.start do
         
     | 
| 
      
 13 
     | 
    
         
            +
                command_name 'spec'
         
     | 
| 
      
 14 
     | 
    
         
            +
                add_filter 'spec'
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            require "bundler/setup"
         
     | 
| 
      
 19 
     | 
    
         
            +
            require "benchmark-malloc"
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            RSpec.configure do |config|
         
     | 
| 
      
 22 
     | 
    
         
            +
              # Enable flags like --only-failures and --next-failure
         
     | 
| 
      
 23 
     | 
    
         
            +
              config.example_status_persistence_file_path = ".rspec_status"
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              # Disable RSpec exposing methods globally on `Module` and `main`
         
     | 
| 
      
 26 
     | 
    
         
            +
              config.disable_monkey_patching!
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              config.expect_with :rspec do |c|
         
     | 
| 
      
 29 
     | 
    
         
            +
                c.syntax = :expect
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Benchmark::Malloc::Allocation do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it "gathers info about allocated object" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                object = Object.new
         
     | 
| 
      
 6 
     | 
    
         
            +
                alloc = described_class.new(object)
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                expect(alloc.memsize).to be <= 40
         
     | 
| 
      
 9 
     | 
    
         
            +
                expect(alloc.source_line).to eq(nil)
         
     | 
| 
      
 10 
     | 
    
         
            +
                expect(alloc.method_id).to eq(nil)
         
     | 
| 
      
 11 
     | 
    
         
            +
                expect(alloc.class_path).to eq(nil)
         
     | 
| 
      
 12 
     | 
    
         
            +
                expect(alloc.source_file).to eq(nil)
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              it "extracts allocation info" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                object = Object.new
         
     | 
| 
      
 17 
     | 
    
         
            +
                alloc = described_class.new(object)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                extracted = alloc.extract(:class, :memsize)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                expect(extracted[0]).to eq(Object)
         
     | 
| 
      
 22 
     | 
    
         
            +
                expect(extracted[1]).to be <= 40
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Benchmark::Malloc::AllocationSet do
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              def make_allocation(object)
         
     | 
| 
      
 6 
     | 
    
         
            +
                Benchmark::Malloc::Allocation.new(object)
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              it "counts allocated objects" do
         
     | 
| 
      
 10 
     | 
    
         
            +
                object_alloc = make_allocation(Object.new)
         
     | 
| 
      
 11 
     | 
    
         
            +
                hash_alloc = make_allocation({Object.new => :foo})
         
     | 
| 
      
 12 
     | 
    
         
            +
                string_alloc = make_allocation(:bar)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                allocations = [object_alloc, hash_alloc, string_alloc]
         
     | 
| 
      
 15 
     | 
    
         
            +
                alloc_set = described_class.new(allocations)
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                expect(alloc_set.count_objects).to eq({Hash => 1, Object => 1, Symbol => 1})
         
     | 
| 
      
 18 
     | 
    
         
            +
                expect(alloc_set.total_objects).to eq(3)
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              it "counts allocated memory" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                object_alloc = make_allocation(Object.new)
         
     | 
| 
      
 23 
     | 
    
         
            +
                hash_alloc = make_allocation({Object.new => :foo})
         
     | 
| 
      
 24 
     | 
    
         
            +
                string_alloc = make_allocation(:bar)
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                allocations = [object_alloc, hash_alloc, string_alloc]
         
     | 
| 
      
 27 
     | 
    
         
            +
                alloc_set = described_class.new(allocations)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                expect(alloc_set.count_memory[Hash]).to be <= 240
         
     | 
| 
      
 30 
     | 
    
         
            +
                expect(alloc_set.count_memory[Object]).to be <= 40
         
     | 
| 
      
 31 
     | 
    
         
            +
                expect(alloc_set.count_memory[Symbol]).to eq 0
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                expect(alloc_set.total_memory).to be < 300
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              it "filters allocated objects" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                object_alloc = make_allocation(Object.new)
         
     | 
| 
      
 38 
     | 
    
         
            +
                hash_alloc = make_allocation({Object.new => :foo})
         
     | 
| 
      
 39 
     | 
    
         
            +
                string_alloc = make_allocation(:bar)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                allocations = [object_alloc, hash_alloc, string_alloc]
         
     | 
| 
      
 42 
     | 
    
         
            +
                alloc_set = described_class.new(allocations)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                expect(alloc_set.filter(Object)).to eq([object_alloc])
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            RSpec.describe Benchmark::Malloc do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it "traces only new object allocations" do
         
     | 
| 
      
 5 
     | 
    
         
            +
                %i[foo bar baz].freeze
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                sample = described_class.run do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  %i[foo bar baz].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                expect(sample.allocated.total_objects).to eq(1)
         
     | 
| 
      
 12 
     | 
    
         
            +
                expect(sample.allocated.total_memory).to be <= 40
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              it "traces block assigned instances" do
         
     | 
| 
      
 16 
     | 
    
         
            +
                memory = described_class.new
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                sample = memory.run do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  _new_object = Object.new
         
     | 
| 
      
 20 
     | 
    
         
            +
                  _new_array  = [:baz]
         
     | 
| 
      
 21 
     | 
    
         
            +
                  _new_string = 'foo' + 'baz'
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                # allocated
         
     | 
| 
      
 25 
     | 
    
         
            +
                expect(sample.allocated.total_objects).to be <= 5
         
     | 
| 
      
 26 
     | 
    
         
            +
                expect(sample.allocated.total_memory).to be <= 200
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                expect(sample.allocated.count_objects[Object]).to eq(1)
         
     | 
| 
      
 29 
     | 
    
         
            +
                expect(sample.allocated.count_objects[Array]).to eq(1)
         
     | 
| 
      
 30 
     | 
    
         
            +
                expect(sample.allocated.count_objects[String]).to be <= 3
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                expect(sample.allocated.count_memory[Object]).to be <= 40
         
     | 
| 
      
 33 
     | 
    
         
            +
                expect(sample.allocated.count_memory[String]).to be <= 120
         
     | 
| 
      
 34 
     | 
    
         
            +
                expect(sample.allocated.count_memory[Array]).to be <= 40
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                # retained
         
     | 
| 
      
 37 
     | 
    
         
            +
                expect(sample.retained.total_objects).to be <= 5
         
     | 
| 
      
 38 
     | 
    
         
            +
                expect(sample.retained.total_memory).to be <= 200
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                expect(sample.retained.count_objects[Object]).to eq(1)
         
     | 
| 
      
 41 
     | 
    
         
            +
                expect(sample.retained.count_objects[Array]).to eq(1)
         
     | 
| 
      
 42 
     | 
    
         
            +
                expect(sample.retained.count_objects[String]).to be <= 3
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                expect(sample.retained.count_memory[Object]).to be <= 40
         
     | 
| 
      
 45 
     | 
    
         
            +
                expect(sample.retained.count_memory[String]).to be <= 120
         
     | 
| 
      
 46 
     | 
    
         
            +
                expect(sample.retained.count_memory[Array]).to be <= 40
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              it "traces large number of objects" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                result = described_class.run do
         
     | 
| 
      
 51 
     | 
    
         
            +
                  10.times { |i| [i.to_s, {}] }
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                expect(result.allocated.total_objects).to eq(10 * 3)
         
     | 
| 
      
 55 
     | 
    
         
            +
                expect(result.allocated.total_memory).to be <= (3120)
         
     | 
| 
      
 56 
     | 
    
         
            +
                expect(result.allocated.count_objects).to eq({
         
     | 
| 
      
 57 
     | 
    
         
            +
                  Array => 10, String => 10, Hash => 10})
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                # memory
         
     | 
| 
      
 60 
     | 
    
         
            +
                expect(result.allocated.count_memory[Array]).to be <= 400
         
     | 
| 
      
 61 
     | 
    
         
            +
                expect(result.allocated.count_memory[String]).to be <= 400
         
     | 
| 
      
 62 
     | 
    
         
            +
                expect(result.allocated.count_memory[Hash]).to be <= 2400
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              it "raises when stopped without starting" do
         
     | 
| 
      
 66 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 67 
     | 
    
         
            +
                  described_class.new.stop
         
     | 
| 
      
 68 
     | 
    
         
            +
                }.to raise_error(Benchmark::Malloc::Error, "not started yet")
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              it "raises when started again" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 73 
     | 
    
         
            +
                  malloc = described_class.new
         
     | 
| 
      
 74 
     | 
    
         
            +
                  malloc.start
         
     | 
| 
      
 75 
     | 
    
         
            +
                  malloc.start
         
     | 
| 
      
 76 
     | 
    
         
            +
                }.to raise_error(Benchmark::Malloc::Error, "already running")
         
     | 
| 
      
 77 
     | 
    
         
            +
              end
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
    
        data/tasks/console.rake
    ADDED
    
    
    
        data/tasks/coverage.rake
    ADDED
    
    
    
        data/tasks/spec.rake
    ADDED
    
    | 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'rspec/core/rake_task'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              desc 'Run all specs'
         
     | 
| 
      
 7 
     | 
    
         
            +
              RSpec::Core::RakeTask.new(:spec) do |task|
         
     | 
| 
      
 8 
     | 
    
         
            +
                task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              namespace :spec do
         
     | 
| 
      
 12 
     | 
    
         
            +
                desc 'Run unit specs'
         
     | 
| 
      
 13 
     | 
    
         
            +
                RSpec::Core::RakeTask.new(:unit) do |task|
         
     | 
| 
      
 14 
     | 
    
         
            +
                  task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                desc 'Run integration specs'
         
     | 
| 
      
 18 
     | 
    
         
            +
                RSpec::Core::RakeTask.new(:integration) do |task|
         
     | 
| 
      
 19 
     | 
    
         
            +
                  task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                desc 'Run performance specs'
         
     | 
| 
      
 23 
     | 
    
         
            +
                RSpec::Core::RakeTask.new(:perf) do |task|
         
     | 
| 
      
 24 
     | 
    
         
            +
                  task.pattern = 'spec/performance{,/*/**}/*_spec.rb'
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 29 
     | 
    
         
            +
              %w[spec spec:unit spec:integration spec:perf].each do |name|
         
     | 
| 
      
 30 
     | 
    
         
            +
                task name do
         
     | 
| 
      
 31 
     | 
    
         
            +
                  $stderr.puts "In order to run #{name}, do `gem install rspec`"
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,106 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: benchmark-malloc
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Piotr Murach
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: exe
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2019-04-06 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: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '3.0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            description: Trace memory allocations and collect stats.
         
     | 
| 
      
 56 
     | 
    
         
            +
            email:
         
     | 
| 
      
 57 
     | 
    
         
            +
            - me@piotrmurach.com
         
     | 
| 
      
 58 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 59 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 60 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 61 
     | 
    
         
            +
            files:
         
     | 
| 
      
 62 
     | 
    
         
            +
            - CHANGELOG.md
         
     | 
| 
      
 63 
     | 
    
         
            +
            - LICENSE.txt
         
     | 
| 
      
 64 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 65 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 66 
     | 
    
         
            +
            - benchmark-malloc.gemspec
         
     | 
| 
      
 67 
     | 
    
         
            +
            - lib/benchmark-malloc.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
            - lib/benchmark/malloc.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            - lib/benchmark/malloc/allocation.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - lib/benchmark/malloc/allocation_result.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
            - lib/benchmark/malloc/allocation_set.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/benchmark/malloc/version.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
            - spec/unit/allocation/new_spec.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
            - spec/unit/allocation_set/new_spec.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
            - spec/unit/run_spec.rb
         
     | 
| 
      
 77 
     | 
    
         
            +
            - tasks/console.rake
         
     | 
| 
      
 78 
     | 
    
         
            +
            - tasks/coverage.rake
         
     | 
| 
      
 79 
     | 
    
         
            +
            - tasks/spec.rake
         
     | 
| 
      
 80 
     | 
    
         
            +
            homepage: https://github.com/piotrmurach/benchmark-malloc
         
     | 
| 
      
 81 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 82 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 83 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 84 
     | 
    
         
            +
              homepage_uri: https://github.com/piotrmurach/benchmark-malloc
         
     | 
| 
      
 85 
     | 
    
         
            +
              source_code_uri: https://github.com/piotrmurach/benchmark-malloc
         
     | 
| 
      
 86 
     | 
    
         
            +
              changelog_uri: https://github.com/piotrmurach/benchmark-malloc/CHANGELOG.md
         
     | 
| 
      
 87 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 88 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 89 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 90 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 91 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 92 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 93 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 94 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 95 
     | 
    
         
            +
                  version: 2.1.0
         
     | 
| 
      
 96 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 97 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 98 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 99 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 100 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 101 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 102 
     | 
    
         
            +
            rubygems_version: 3.0.3
         
     | 
| 
      
 103 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 104 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 105 
     | 
    
         
            +
            summary: Trace memory allocations and collect stats.
         
     | 
| 
      
 106 
     | 
    
         
            +
            test_files: []
         
     |