rspec-gc-control 1.0.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.
- data/CHANGELOG.md +14 -0
- data/LICENSE +22 -0
- data/README.md +60 -0
- data/lib/rspec-gc-control.rb +6 -0
- data/lib/rspec-gc-control/base_text_formatter.rb +31 -0
- data/lib/rspec-gc-control/configuration.rb +62 -0
- data/lib/rspec-gc-control/example.rb +26 -0
- data/rspec-gc-control.gemspec +47 -0
- metadata +74 -0
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
### dev
|
2
|
+
[full changelog](http://github.com/MrJoy/rspec-gc-control/compare/v1.0.0...master)
|
3
|
+
|
4
|
+
Changes
|
5
|
+
|
6
|
+
* Forgot to update changelog before tagging release.
|
7
|
+
|
8
|
+
|
9
|
+
### v1.0.0
|
10
|
+
[full changelog](http://github.com/MrJoy/rspec-gc-control/compare/1d2bd61...v1.0.0)
|
11
|
+
|
12
|
+
Initial Version
|
13
|
+
|
14
|
+
* Add support for controlling how often GC runs on RSpec 2.11.1.
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2012 Jon Frisby
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# rspec-gc-control
|
2
|
+
|
3
|
+
## Summary
|
4
|
+
|
5
|
+
This gem extends RSpec to allow you to control how often GC cycles happen
|
6
|
+
in order to trade increased memory usage for faster test runs. It's an
|
7
|
+
encapsulated and reusable version of the code shown in this article:
|
8
|
+
|
9
|
+
<http://www.rubyinside.com/careful-cutting-to-get-faster-rspec-runs-with-rails-5207.html>
|
10
|
+
|
11
|
+
|
12
|
+
## Requirements
|
13
|
+
|
14
|
+
For this to work, you need a Ruby that supports explicit control over the
|
15
|
+
garbage collector, and RSpec 2.11.1 or higher.
|
16
|
+
|
17
|
+
Supported Rubies include MRI 1.9.2 and 1.9.3, and most likely Rubinius.
|
18
|
+
|
19
|
+
Unsupported Rubies are:
|
20
|
+
|
21
|
+
* MRI 1.8.x: No support for `GC.count`.
|
22
|
+
* JRuby: `GC.enable` / `GC.disable` are no-ops.
|
23
|
+
|
24
|
+
On unsupported platforms, attempting to enable explicit GC control via this
|
25
|
+
plugin will produce a warning and have no other effect.
|
26
|
+
|
27
|
+
|
28
|
+
## Installation and Usage
|
29
|
+
|
30
|
+
Install the gem:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
gem install rspec-gc-control
|
34
|
+
```
|
35
|
+
|
36
|
+
Or if you're using bundler, add this line to your `Gemfile` and run
|
37
|
+
`bundle install`:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
gem 'rspec-gc-control'
|
41
|
+
```
|
42
|
+
|
43
|
+
Once you have the gem installed, edit your `spec_helper.rb` file to set
|
44
|
+
`gc_every_n_examples` to an appropriate value. You may want to play with this
|
45
|
+
value while watching memory consumption for the process to get a feeling for
|
46
|
+
how significant a tradeoff you're making in terms of increased memory usage.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
RSpec.configure do |c|
|
50
|
+
c.gc_every_n_examples = 10
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
You'll know it's working if you see output like the following at the end of
|
55
|
+
your test run:
|
56
|
+
|
57
|
+
```
|
58
|
+
Finished in 6.45 seconds (including 7 forced GC cycle(s), totalling 0.67116 seconds)
|
59
|
+
71 examples, 0 failures, 1 pending
|
60
|
+
```
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rspec/core/formatters/base_formatter'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
module Formatters
|
6
|
+
|
7
|
+
class BaseTextFormatter < BaseFormatter
|
8
|
+
|
9
|
+
# Overridden version of this method, to include output about forced GC
|
10
|
+
# count and duration, if explicit GC control is enabled.
|
11
|
+
def dump_summary(duration, example_count, failure_count, pending_count)
|
12
|
+
super(duration, example_count, failure_count, pending_count)
|
13
|
+
# Don't print out profiled info if there are failures, it just clutters the output
|
14
|
+
dump_profile if profile_examples? && failure_count == 0
|
15
|
+
output.print "\nFinished in #{format_duration(duration)}"
|
16
|
+
|
17
|
+
gc_times = examples.map { |ex| ex.execution_result[:gc_time] }.select { |t| !t.nil? && (t > 0) }
|
18
|
+
if(gc_times.count > 0)
|
19
|
+
gc_count = gc_times.count
|
20
|
+
gc_time = gc_times.reduce(:+)
|
21
|
+
output.print " (including #{gc_count} forced GC cycle(s), totalling #{format_duration(gc_time)})"
|
22
|
+
end
|
23
|
+
output.print "\n"
|
24
|
+
output.puts colorise_summary(summary_line(example_count, failure_count, pending_count))
|
25
|
+
dump_commands_to_rerun_failed_examples
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'rspec/core/configuration'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
# Extensions to RSpec::Core::Configuration to allow configuration of
|
6
|
+
# desired GC behavior.
|
7
|
+
class Configuration
|
8
|
+
# @private
|
9
|
+
define_reader :gc_every_n_examples
|
10
|
+
|
11
|
+
# @private
|
12
|
+
alias_method :initialize_without_gc, :initialize
|
13
|
+
|
14
|
+
# Overridden constructor to initialize `gc_every_n_examples` to 0.
|
15
|
+
# This disables the explicit GC control.
|
16
|
+
def initialize
|
17
|
+
initialize_without_gc
|
18
|
+
@gc_every_n_examples = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
# @private
|
22
|
+
def gc_if_needed
|
23
|
+
gc_time = 0
|
24
|
+
if(@gc_every_n_examples > 0)
|
25
|
+
@test_counter = -1 if(!defined?(@test_counter))
|
26
|
+
@test_counter += 1
|
27
|
+
if(@test_counter >= (@gc_every_n_examples - 1))
|
28
|
+
t_before = Time.now
|
29
|
+
GC.enable
|
30
|
+
GC.start
|
31
|
+
GC.disable
|
32
|
+
gc_time = Time.now - t_before
|
33
|
+
|
34
|
+
@test_counter = 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return gc_time
|
38
|
+
end
|
39
|
+
|
40
|
+
# If set to a value above 0, turns automatic GC off and runs it only
|
41
|
+
# every N tests, which can result in higher peak memory usage but lower
|
42
|
+
# total execution time.
|
43
|
+
def gc_every_n_examples=(n)
|
44
|
+
if(defined?(JRuby))
|
45
|
+
warn "Ignoring gc_every_n_examples because JRuby doesn't support GC control."
|
46
|
+
return
|
47
|
+
end
|
48
|
+
if(!GC.respond_to?(:count))
|
49
|
+
warn "Ignoring gc_every_n_examples because this Ruby implementation doesn't implement GC.count."
|
50
|
+
return
|
51
|
+
end
|
52
|
+
@gc_every_n_examples = n
|
53
|
+
if(@gc_every_n_examples > 0)
|
54
|
+
GC.disable
|
55
|
+
else
|
56
|
+
GC.enable
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rspec/core/example'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
# Extensions to RSpec::Core::Example to perform explicit GC and capture
|
6
|
+
# GC execution time.
|
7
|
+
class Example
|
8
|
+
private
|
9
|
+
|
10
|
+
undef :record_finished
|
11
|
+
def record_finished(status, results={})
|
12
|
+
finished_at = Time.now
|
13
|
+
record results.merge(:status => status, :finished_at => finished_at, :run_time => (finished_at - (execution_result[:started_at] + (execution_result[:gc_time] || 0))))
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :run_after_each_without_gc, :run_after_each
|
17
|
+
|
18
|
+
def run_after_each
|
19
|
+
run_after_each_without_gc
|
20
|
+
ensure
|
21
|
+
execution_result[:gc_time] = RSpec.configuration.gc_if_needed
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "rspec-gc-control"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jon Frisby"]
|
12
|
+
s.date = "2012-08-12"
|
13
|
+
s.description = "Explicit control over garbage collection behavior for RSpec."
|
14
|
+
s.email = "jfrisby@mrjoy.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"CHANGELOG.md",
|
21
|
+
"LICENSE",
|
22
|
+
"README.md",
|
23
|
+
"lib/rspec-gc-control.rb",
|
24
|
+
"lib/rspec-gc-control/base_text_formatter.rb",
|
25
|
+
"lib/rspec-gc-control/configuration.rb",
|
26
|
+
"lib/rspec-gc-control/example.rb",
|
27
|
+
"rspec-gc-control.gemspec"
|
28
|
+
]
|
29
|
+
s.homepage = "http://MrJoy.com"
|
30
|
+
s.licenses = ["MIT"]
|
31
|
+
s.require_paths = ["lib"]
|
32
|
+
s.rubygems_version = "1.8.24"
|
33
|
+
s.summary = "Explicit control over garbage collection behavior for RSpec."
|
34
|
+
|
35
|
+
if s.respond_to? :specification_version then
|
36
|
+
s.specification_version = 3
|
37
|
+
|
38
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
39
|
+
s.add_runtime_dependency(%q<rspec-core>, [">= 2.11.1"])
|
40
|
+
else
|
41
|
+
s.add_dependency(%q<rspec-core>, [">= 2.11.1"])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
s.add_dependency(%q<rspec-core>, [">= 2.11.1"])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rspec-gc-control
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Frisby
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec-core
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.11.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.11.1
|
30
|
+
description: Explicit control over garbage collection behavior for RSpec.
|
31
|
+
email: jfrisby@mrjoy.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files:
|
35
|
+
- LICENSE
|
36
|
+
- README.md
|
37
|
+
files:
|
38
|
+
- CHANGELOG.md
|
39
|
+
- LICENSE
|
40
|
+
- README.md
|
41
|
+
- lib/rspec-gc-control.rb
|
42
|
+
- lib/rspec-gc-control/base_text_formatter.rb
|
43
|
+
- lib/rspec-gc-control/configuration.rb
|
44
|
+
- lib/rspec-gc-control/example.rb
|
45
|
+
- rspec-gc-control.gemspec
|
46
|
+
homepage: http://MrJoy.com
|
47
|
+
licenses:
|
48
|
+
- MIT
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
hash: -2268877769317612634
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
requirements: []
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.8.24
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: Explicit control over garbage collection behavior for RSpec.
|
74
|
+
test_files: []
|