debug_timer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 214a4308350f211e2e5e65095f27d2e6a35acf55
4
+ data.tar.gz: 4e9221eae9d9abcc136f0d411eb0afa4f3bc9805
5
+ SHA512:
6
+ metadata.gz: fa1ca0cb8ae667c050e49e75b6f7cc27796f690c2e401d9637a69610f924a36f745e272f6c9c741ec9be5ea7121257517a3f3b7f3e1442ddeefb7fa7b6ea9e36
7
+ data.tar.gz: bd4b0beede7e6a8cdce1ffe6130b9149c89d3ebacc8fda5fae8c5cfb6f3deea1a8e0e8412fc720862549abade8581461f6e55d8ab311dddf0c71b44119f49735
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format progress
3
+ --require spec_helper
4
+ --pattern "spec/**/*_spec.rb"
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.1.5
5
+ - 2.2.0
6
+ - 2.3.1
7
+ - 2.4.0
@@ -0,0 +1,2 @@
1
+ === 0.1.0
2
+ - Adding the ability to output gc_stats
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in debug_timer.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Austin Fonacier
2
+
3
+ MIT License
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
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,140 @@
1
+ # DebugTimer
2
+
3
+ This gem is to help debug slow portions of the code. When RubyProf isn't enough and you need to get deeper into the code base this is the solution. The output will look like this:
4
+
5
+ ```
6
+ 1.8040 └── search
7
+ 1.0554    └── 1st
8
+ 0.0033        └── config
9
+ 0.0001        └── 1.1
10
+ 0.6579        └── 1.2
11
+ 0.0087            └── 1.2.1
12
+ 0.0075            └── 1.2.2
13
+ 0.6416            └── set_custom_variable
14
+ 0.3941        └── 1.3
15
+ 0.3938            └── 1.3.1
16
+ 0.0002            └── 1.3.2
17
+ 0.1487    └── 2nd
18
+ 0.5999    └── 3rd
19
+ 0.0133        └── presenter
20
+ 0.0023        └── serialize
21
+ 0.5843        └── respond_to
22
+ 0.5842            └── render
23
+ 0.1506                └── presenter.view
24
+
25
+ ```
26
+
27
+ ## Installation
28
+
29
+ Add this line to your application's Gemfile:
30
+
31
+ ```ruby
32
+ gem 'debug_timer'
33
+ ```
34
+
35
+ And then execute:
36
+
37
+ $ bundle
38
+
39
+ Or install it yourself as:
40
+
41
+ $ gem install debug_timer
42
+
43
+ ### Configuration
44
+
45
+ You can add your logger instance if you want:
46
+
47
+ ```ruby
48
+ # Straight assignment
49
+ DebugTimer.logger = Logger.new('asdf')
50
+ DebugTimer.object_allocations = true
51
+
52
+ # or config assignment
53
+ DebugTimer.config do |config|
54
+ config.logger = Logger.new('asdf')
55
+ config.object_allocations = true
56
+ end
57
+
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ To use DebugTimer simply wrap the code you want to time in a block.
63
+
64
+ ```ruby
65
+ DebugTimer.start('search function') do
66
+ Search.searchysearchsearch('search query')
67
+ SomeOtherCode.DoWhatever?
68
+
69
+ IhazFunction?
70
+ end
71
+ ```
72
+
73
+ When you run that piece of code you will see in your log. The number on the left is the time that block of code took to run
74
+
75
+ ```
76
+ 1.8040 └── search function
77
+ ```
78
+
79
+ ### Nesting
80
+
81
+ You can nest blocks within blocks.
82
+
83
+ ```ruby
84
+ DebugTimer.start('search function') do
85
+ Search.searchysearchsearch('search query')
86
+
87
+ DebugTimer.start('Some other code') do
88
+ SomeOtherCode.DoWhatever?
89
+ end
90
+
91
+ IhazFunction?
92
+ end
93
+ ```
94
+
95
+ And the output will look like:
96
+
97
+ ```
98
+ 1.8040 └── search function
99
+ 1.0554    └── Some other code
100
+ ```
101
+
102
+ ### Object Allocations
103
+ ```ruby
104
+
105
+ # Enable it
106
+ DebugTimer.object_allocations = true
107
+
108
+ # Time
109
+ DebugTimer.start('search function') do
110
+ Search.todo('in here')
111
+ end
112
+ ```
113
+
114
+ And the output will look like:
115
+ ```
116
+ INFO -- : 0.0036 | T_OBJECT: 1 | FREE: -91 └── search function
117
+ ```
118
+
119
+ The second pipe is the is ObjectSpace's T_OBJECT change
120
+
121
+ The third pipe is the ObjectSpace's :FREE change
122
+
123
+
124
+ ## Running Specs
125
+
126
+ ```
127
+ > rake
128
+
129
+ Finished in 0.00926 seconds (files took 0.11604 seconds to load)
130
+ 5 examples, 0 failures
131
+ ```
132
+
133
+
134
+ ## Contributing
135
+
136
+ 1. Fork it ( https://github.com/[my-github-username]/debug_timer/fork )
137
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
138
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
139
+ 4. Push to the branch (`git push origin my-new-feature`)
140
+ 5. Create a new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new('spec')
5
+ task :default => :spec
6
+ task :test => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'debug_timer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "debug_timer"
8
+ spec.version = DebugTimer::VERSION
9
+ spec.authors = ["Jorge Urias", "Austin Fonacier"]
10
+ spec.email = ["jurias@spokeo.com", "austinrf@gmail.com"]
11
+ spec.summary = "When RubyProf has failed you, time your individual code components."
12
+ spec.description = "Nest code blocks and time them easily to grab a greater insight on what is happening to your code."
13
+ spec.homepage = "https://github.com/austinrfnd/debug_timer"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "3.3.0"
24
+ end
@@ -0,0 +1,42 @@
1
+ require 'logger'
2
+ require "debug_timer/version"
3
+ require "debug_timer/config"
4
+ require "debug_timer/logger"
5
+ require "debug_timer/node"
6
+ require "debug_timer/node_printer"
7
+
8
+ module DebugTimer
9
+ def self.start(name = '---', &block)
10
+ parent = @current_node
11
+
12
+ @current_node = Node.new(name)
13
+ result = yield
14
+ @current_node.stop()
15
+
16
+ if parent
17
+ parent.children << @current_node
18
+ else
19
+ print_tree(@current_node)
20
+ end
21
+
22
+ result
23
+ ensure
24
+ @current_node = parent
25
+ end
26
+
27
+ private
28
+
29
+ def self.gather_nodes(node, depth = 0)
30
+ nodes = []
31
+ nodes << node.print(depth: depth)
32
+ node.children.each do |node|
33
+ nodes = nodes + gather_nodes(node, depth+1)
34
+ end
35
+ nodes
36
+ end
37
+
38
+ def self.print_tree(node)
39
+ nodes_output = gather_nodes(node, 0).join("\n")
40
+ logger.info(nodes_output)
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module DebugTimer
2
+ @@object_allocations = false
3
+
4
+ def self.configure
5
+ yield self
6
+ end
7
+
8
+ def self.object_allocations=(object_allocations)
9
+ @@object_allocations = object_allocations
10
+ end
11
+
12
+ def self.object_allocations?
13
+ @@object_allocations
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module DebugTimer
2
+ def self.logger=(logger)
3
+ @@logger = logger
4
+ end
5
+
6
+ def self.logger
7
+ @@logger ||= Logger.new($stdout)
8
+ end
9
+ end
@@ -0,0 +1,38 @@
1
+ module DebugTimer
2
+ class Node
3
+ attr_reader :name, :children, :start_time, :parent, :time_elapsed, :start_gc_stats, :end_gc_stats
4
+ def initialize(name)
5
+ @name = name
6
+ @children = []
7
+ if DebugTimer.object_allocations?
8
+ grab_object_allocations(true)
9
+ end
10
+ @start_time = Time.now
11
+ end
12
+
13
+ def stop
14
+ @time_elapsed = Time.now - start_time
15
+ if DebugTimer.object_allocations?
16
+ grab_object_allocations(false)
17
+ end
18
+ end
19
+
20
+ def print(depth:)
21
+ NodePrinter.new(self).print(depth)
22
+ end
23
+
24
+ private
25
+
26
+ def grab_object_allocations(start)
27
+ if start
28
+ # GC.disable
29
+ # puts ObjectSpace.count_objects.inspect
30
+ @start_gc_stats = ObjectSpace.count_objects
31
+ else
32
+ # puts ObjectSpace.count_objects.inspect
33
+ @end_gc_stats = ObjectSpace.count_objects
34
+ # GC.enable
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ module DebugTimer
2
+ class NodePrinter
3
+ def initialize(node)
4
+ @node = node
5
+ end
6
+
7
+ # Should return a string of the printed
8
+ def print(depth)
9
+ spaces = " ".freeze * depth
10
+ "#{left_stats} #{spaces} └── #{@node.name}"
11
+ end
12
+
13
+ private
14
+ def left_stats
15
+ stats = [seconds_elapsed]
16
+ if DebugTimer.object_allocations?
17
+ stats << "T_OBJECT: #{total_objects_allocated}"
18
+ stats << "FREE: #{total_free_count}"
19
+ end
20
+ stats.join(" | ")
21
+ end
22
+
23
+ def total_objects_allocated
24
+ @node.end_gc_stats[:T_OBJECT] - @node.start_gc_stats[:T_OBJECT]
25
+ end
26
+
27
+ def total_free_count
28
+ @node.end_gc_stats[:FREE] - @node.start_gc_stats[:FREE]
29
+ end
30
+
31
+ def seconds_elapsed
32
+ [0.0001, @node.time_elapsed].max.round(4).to_s.ljust(6, '0'.freeze)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module DebugTimer
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,14 @@
1
+ describe "DebugTimer configure" do
2
+ it "should default object_allocations to false" do
3
+ expect(DebugTimer.object_allocations?).to be_falsey
4
+ end
5
+
6
+ context 'configure' do
7
+ it "should return set object_allocations" do
8
+ DebugTimer.configure do |config|
9
+ config.object_allocations = true
10
+ end
11
+ expect(DebugTimer.object_allocations?).to be_truthy
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ describe DebugTimer do
2
+ context 'start' do
3
+ it "should yield the block" do
4
+ DebugTimer.object_allocations = true
5
+ yielded = DebugTimer.start("yo ho yo ho a pirate's life for me") do
6
+ DebugTimer.start('pirate insider') do
7
+ "Black"
8
+ end
9
+ attr = []
10
+ 8.times do |x|
11
+ attr << "foobar#{x}"
12
+ attr << Array.new(1_000_000/8)
13
+ end
14
+ 'Jack'
15
+ end
16
+ expect(yielded).to eql("Jack")
17
+ DebugTimer.object_allocations = false
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,34 @@
1
+ describe DebugTimer::NodePrinter do
2
+ let :node do
3
+ DebugTimer::Node.new('asdf')
4
+ end
5
+ context 'object_allocations set to true' do
6
+ before :each do
7
+ DebugTimer.object_allocations = true
8
+ end
9
+
10
+ it "should print a string" do
11
+ node.stop
12
+ printer = DebugTimer::NodePrinter.new(node)
13
+ expect(printer.print(1)).to be_kind_of(String)
14
+ end
15
+
16
+ it "should include data allocation output" do
17
+ node.stop
18
+ printer = DebugTimer::NodePrinter.new(node)
19
+ expect(printer.print(1)).to match(/T_OBJECT/)
20
+ end
21
+ end
22
+
23
+ context "object_allocations set to false" do
24
+ before :each do
25
+ DebugTimer.object_allocations = false
26
+ end
27
+
28
+ it "should not include data allocation output" do
29
+ node.stop
30
+ printer = DebugTimer::NodePrinter.new(node)
31
+ expect(printer.print(1)).to_not match(/T_OBJECT/)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ describe DebugTimer::Node do
2
+ let :node do
3
+ n = DebugTimer::Node.new('asdf')
4
+ 'asdf'
5
+ n.stop
6
+ n
7
+ end
8
+
9
+ describe 'initialize' do
10
+ it "should a name" do
11
+ expect(node.name).to eql('asdf')
12
+ end
13
+
14
+ it "should initialize with empty children" do
15
+ expect(node.children).to eql([])
16
+ end
17
+
18
+ it "should have a start_time" do
19
+ k = Time.now
20
+ expect(Time).to receive(:now) { k }
21
+ node = DebugTimer::Node.new('asdf2')
22
+ expect(node.start_time).to eql(k)
23
+ end
24
+ end
25
+
26
+ context 'stop' do
27
+ it "should set @time_elapsed" do
28
+ node.stop
29
+ expect(node.time_elapsed).to_not be_nil
30
+ end
31
+ end
32
+ end
@@ -0,0 +1 @@
1
+ require 'debug_timer'
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: debug_timer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jorge Urias
8
+ - Austin Fonacier
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-07-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.7'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.7'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '='
47
+ - !ruby/object:Gem::Version
48
+ version: 3.3.0
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '='
54
+ - !ruby/object:Gem::Version
55
+ version: 3.3.0
56
+ description: Nest code blocks and time them easily to grab a greater insight on what
57
+ is happening to your code.
58
+ email:
59
+ - jurias@spokeo.com
60
+ - austinrf@gmail.com
61
+ executables: []
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - ".gitignore"
66
+ - ".rspec"
67
+ - ".travis.yml"
68
+ - Changelog.rdoc
69
+ - Gemfile
70
+ - LICENSE.txt
71
+ - README.md
72
+ - Rakefile
73
+ - debug_timer.gemspec
74
+ - lib/debug_timer.rb
75
+ - lib/debug_timer/config.rb
76
+ - lib/debug_timer/logger.rb
77
+ - lib/debug_timer/node.rb
78
+ - lib/debug_timer/node_printer.rb
79
+ - lib/debug_timer/version.rb
80
+ - spec/lib/config_spec.rb
81
+ - spec/lib/debug_timer_spec.rb
82
+ - spec/lib/node_printer_spec.rb
83
+ - spec/lib/node_spec.rb
84
+ - spec/spec_helper.rb
85
+ homepage: https://github.com/austinrfnd/debug_timer
86
+ licenses:
87
+ - MIT
88
+ metadata: {}
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project:
105
+ rubygems_version: 2.6.11
106
+ signing_key:
107
+ specification_version: 4
108
+ summary: When RubyProf has failed you, time your individual code components.
109
+ test_files:
110
+ - spec/lib/config_spec.rb
111
+ - spec/lib/debug_timer_spec.rb
112
+ - spec/lib/node_printer_spec.rb
113
+ - spec/lib/node_spec.rb
114
+ - spec/spec_helper.rb