time_method 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: f772b3b225ddfb7f9ea1139a0f5ee224473361d7
4
+ data.tar.gz: 077a6d1cb862368364e73d7a9e4fb18262b2d70e
5
+ SHA512:
6
+ metadata.gz: 90d6af20d3084cd37f347bf9cee0ba96f8dc7d14d11e7b3590d21061894e4d48fe0cb16a789b3cbcb92fbb76dbe69cf36651ffb92dbfad97b2db5c5b6997c826
7
+ data.tar.gz: b9efdcceb0b84bf72079df9ca46de7cf01570df15c5275a8d0eeb6af0acc14ad60039c49aa2654818e52ca21fcdca9a84f450ff97ca7d177476f96aa442942ba
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.5
5
+ before_install: gem install bundler -v 1.16.1
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in time_method.gemspec
6
+ gemspec
7
+
@@ -0,0 +1,50 @@
1
+ # TimeMethod
2
+
3
+
4
+ TimeMethod is a gem that makes it easy to see the run-time of different methods within Terminal
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'time_method'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install time_method
22
+
23
+ ## Usage
24
+
25
+
26
+ TimeMethod is built upon the excellent gem made here [here](https://github.com/Riskified/timeasure)
27
+
28
+ You can visit the above page for more details on usage. This version has some functionality trimmed down
29
+ and some functionality added. The focus is on development profiling of methods.
30
+
31
+ It outputs two tables at the end of a request/test being run.
32
+
33
+ 1) A list of methods sorted by total run time
34
+
35
+ 2) A list of methods sorted by total execution order
36
+
37
+ ![Table image 1](img_1.png)
38
+
39
+ In order to show these tables, call
40
+ ```StoreMeasurement.instance.print_all```
41
+ at the end of your request.
42
+
43
+ You can also create a middleware to do this.
44
+
45
+ ## Development
46
+
47
+ 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.
48
+
49
+ 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).
50
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
Binary file
@@ -0,0 +1,85 @@
1
+ require_relative "lib/class_methods"
2
+ require_relative "lib/configuration"
3
+ require_relative "lib/measurement"
4
+
5
+ module TimeMethod
6
+ class << self
7
+
8
+ def configure
9
+ yield(configuration)
10
+ end
11
+
12
+ def measure(klass_name: nil, method_name: nil)
13
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
14
+ StoreMeasurement.instance.add_to_stack(
15
+ "in",klass_name,method_name
16
+ )
17
+ block_return_value = yield if block_given?
18
+ StoreMeasurement.instance.add_to_stack(
19
+ "out", klass_name, method_name
20
+ )
21
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
22
+ begin
23
+ measurement = TimeMethod::Measurement.new(
24
+ klass_name: klass_name.to_s,
25
+ method_name: method_name.to_s,
26
+ t0: t0,
27
+ t1: t1
28
+ )
29
+ rescue => e
30
+ puts e,e.backtrace[0..3]
31
+ end
32
+
33
+ block_return_value
34
+ end
35
+
36
+ def print_all_run_times
37
+ StoreMeasurement.instance.print_all
38
+ end
39
+
40
+ def configuration
41
+ @configuration ||= Configuration.new
42
+ end
43
+
44
+ def included(base_class)
45
+ base_class.extend ClassMethods
46
+ # below creates two modules and then makes
47
+ # them accessible through a constant name
48
+ instance_interceptor = const_set(
49
+ instance_interceptor_name_for(base_class),
50
+ interceptor_module_for(base_class)
51
+ )
52
+ class_interceptor = const_set(
53
+ class_interceptor_name_for(base_class),
54
+ interceptor_module_for(base_class)
55
+ )
56
+
57
+ return unless should_run_and_time_methods?
58
+
59
+ base_class.prepend instance_interceptor
60
+ base_class.singleton_class.prepend class_interceptor
61
+ end
62
+
63
+ def instance_interceptor_name_for(base_class)
64
+ "#{base_class.time_method_name}InstanceInterceptor"
65
+ end
66
+
67
+ def class_interceptor_name_for(base_class)
68
+ "#{base_class.time_method_name}ClassInterceptor"
69
+ end
70
+
71
+
72
+ def interceptor_module_for(base_class)
73
+ Module.new do
74
+ @klass_name = base_class
75
+ def self.klass_name
76
+ @klass_name
77
+ end
78
+ end
79
+ end
80
+
81
+ def should_run_and_time_methods?
82
+ configuration.enable_time_method
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,52 @@
1
+ load "#{Rails.root}/lib/time_method/store_measurement.rb"
2
+ module TimeMethod
3
+ module ClassMethods
4
+
5
+ def time_method_name
6
+ name.gsub("::","_")
7
+ end
8
+
9
+ def tracked_instance_methods(*method_names)
10
+ method_names.each do |method_name|
11
+ add_method_to_interceptor(instance_interceptor,method_name)
12
+ end
13
+ end
14
+
15
+ def tracked_class_methods(*method_names)
16
+ method_names.each do |method_name|
17
+ add_method_to_interceptor(class_interceptor,method_name)
18
+ end
19
+ end
20
+ def tracked_private_instance_methods(*method_names)
21
+ tracked_instance_methods(*method_names)
22
+ method_names.each { |method_name| private_interceptor_method(instance_interceptor,method_name)}
23
+ end
24
+
25
+ def tracked_private_class_methods(*method_namess)
26
+ tracked_class_methods(*method_names)
27
+ method_names.each { |method_name| private_interceptor_method(class_interceptor,method_name)}
28
+ end
29
+
30
+ def privatize_interceptor_method(interceptor,method_name)
31
+ interceptor.class_eval {private method_name}
32
+ end
33
+
34
+ def instance_interceptor
35
+ const_get("#{time_method_name}InstanceInterceptor")
36
+ end
37
+
38
+ def class_interceptor
39
+ const_get("#{time_method_name}ClassInterceptor")
40
+ end
41
+
42
+ def add_method_to_interceptor(interceptor,method_name)
43
+ interceptor.class_eval do
44
+ define_method method_name do |*args, &block|
45
+ TimeMethod.measure(klass_name:interceptor.klass_name.to_s,method_name:method_name.to_s) do
46
+ super(*args,&block)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,8 @@
1
+ module TimeMethod
2
+ class Configuration
3
+ attr_accessor :enable_time_method
4
+ def initialize
5
+ @enable_time_method = true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,34 @@
1
+ module TimeMethod
2
+ class Measurement
3
+ attr_accessor :klass_name, :method_name, :segment, :metadata, :t0, :t1,:time
4
+ def initialize(klass_name:, method_name:, t0:, t1:)
5
+ @klass_name = klass_name
6
+ @method_name = method_name
7
+ @t0 = t0
8
+ @t1 = t1
9
+ # @time = runtime_ms
10
+ @time = runtime_seconds
11
+ store_measurement
12
+ end
13
+
14
+ def store_measurement
15
+ StoreMeasurement.instance.store(klass_name:@klass_name,method_name:@method_name,time:@time)
16
+ end
17
+
18
+ def output_stack
19
+ StoreMeasurement.instance.output_stack
20
+ end
21
+
22
+ def runtime
23
+ @runtime_in_milliseconds ||= ((@t1 - @t0) * 1000).round(2)
24
+ end
25
+
26
+ def runtime_ms
27
+ @runtime_in_milliseconds ||= ((@t1 - @t0) * 1000).round(2)
28
+ end
29
+
30
+ def runtime_seconds
31
+ @runtime_in_seconds ||= (@t1 - @t0).round(2)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,93 @@
1
+ module TimeMethod
2
+ class StoreMeasurement
3
+ include Singleton
4
+ def initialize
5
+ @time_for_method = []
6
+ @methods_in_order = []
7
+ @depth = 0
8
+ @full_stack = []
9
+ end
10
+
11
+ def add_to_stack(in_or_out,klass_name,method_name)
12
+ @depth+=1 if in_or_out == "in"
13
+ @depth-=1 if in_or_out == "out"
14
+ mod_klass_name=klass_name.split("::").last
15
+ name="#{mod_klass_name}.#{method_name}"
16
+ end
17
+
18
+ # can add some logic here when/while storing as well
19
+ def store(klass_name:,method_name:,time:)
20
+ mod_klass_name=klass_name.split("::").last
21
+ name="#{mod_klass_name}.#{method_name}"
22
+ @time_for_method.push([name,time,@depth])
23
+ end
24
+
25
+ def make_summary_arr(sort_by:)
26
+ updated_time_for_method = @time_for_method.map{|x| [x[0],(x[1].real*1000).round(2)," "*x[2]]}
27
+ h=updated_time_for_method.group_by{|a| a[0]}
28
+ new_h={}
29
+ h.each do |k,v|
30
+ sum = 0
31
+ count=0
32
+ v.each do |el|
33
+ sum+=el[1]
34
+ count+=1
35
+ end
36
+ avg = (sum/count)
37
+ tabs = v[0][2]
38
+ new_h[k]=[sum,count,avg,tabs]
39
+ end
40
+ new_arr=[]
41
+ new_h.each do |k,v|
42
+ k_with_tabs = v[3]+k
43
+ method_and_class_name=k_with_tabs.scan(/[a-zA-Z::_0-9\t ]+/)
44
+ new_arr.push([*method_and_class_name,*v])
45
+ end
46
+
47
+ if sort_by == "run_time"
48
+ new_arr.map! {|x| [x[0].gsub(" ",""),x[1],x[2].round(0),x[3].round(0),x[4].round(0)]}
49
+ new_arr.sort! {|a,b| b[2] <=> a[2]}
50
+ title = "Sorted List of Methods By Total Run Time"
51
+ elsif sort_by == "execution_order"
52
+ new_arr.map! {|x| [x[0],x[1],x[2].round(0),x[3].round(0),x[4].round(0)]}
53
+ new_arr = new_arr.reverse
54
+ title = "Sorted List of Methods By Total Execution Order"
55
+ end
56
+
57
+ headings=[ "Class Name", "Method Name", "Total Run Time (ms)","# of Calls","Average Time Per Call (ms)"]
58
+ table = Terminal::Table.new :title => title ,:headings => headings do |t|
59
+ t.rows = new_arr
60
+ end
61
+ return table
62
+ end
63
+
64
+ def make_summary_arr_run_time
65
+ @summary_arr = make_summary_arr(sort_by:"run_time")
66
+ end
67
+
68
+ def print_summary_arr_run_time
69
+ puts @summary_arr
70
+ end
71
+
72
+
73
+ def make_summary_arr_execution_order
74
+ @summary_arr_execution_order = make_summary_arr(sort_by:"execution_order")
75
+ end
76
+
77
+ def print_summary_arr_execution_order
78
+ puts @summary_arr_execution_order
79
+ end
80
+
81
+ def print_summary_arr
82
+ puts @summary_arr
83
+ end
84
+
85
+ def print_all
86
+ make_summary_arr_run_time
87
+ make_summary_arr_execution_order
88
+ print_summary_arr_run_time
89
+ print_summary_arr_execution_order
90
+ @time_for_method=[]
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,3 @@
1
+ module TimeMethod
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Eliav Lavi
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,29 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "time_method/version.rb"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "time_method"
8
+ spec.version = TimeMethod::VERSION
9
+ spec.authors = ["Seyon Vasantharajan"]
10
+ spec.email = ["seyon.vasantharajan@gmail.com"]
11
+
12
+ spec.summary = %q{Easily set methods to profile and view run-times in terminal }
13
+ spec.description = <<-DESCRIPTION
14
+ Time Method allows easy setting of runtime without having to alter
15
+ the code of the methods and also allows
16
+ DESCRIPTION
17
+ spec.homepage = "https://github.com/seyonv/time_method"
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib","lib/time_method"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.16"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rspec", "~> 3.0"
28
+ spec.add_development_dependency "terminal-table"
29
+ end
@@ -0,0 +1,85 @@
1
+ require_relative "time_method/class_methods"
2
+ require_relative "time_method/configuration"
3
+ require_relative "time_method/measurement"
4
+
5
+ module TimeMethod
6
+ class << self
7
+
8
+ def configure
9
+ yield(configuration)
10
+ end
11
+
12
+ def measure(klass_name: nil, method_name: nil)
13
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
14
+ StoreMeasurement.instance.add_to_stack(
15
+ "in",klass_name,method_name
16
+ )
17
+ block_return_value = yield if block_given?
18
+ StoreMeasurement.instance.add_to_stack(
19
+ "out", klass_name, method_name
20
+ )
21
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
22
+ begin
23
+ measurement = TimeMethod::Measurement.new(
24
+ klass_name: klass_name.to_s,
25
+ method_name: method_name.to_s,
26
+ t0: t0,
27
+ t1: t1
28
+ )
29
+ rescue => e
30
+ puts e,e.backtrace[0..3]
31
+ end
32
+
33
+ block_return_value
34
+ end
35
+
36
+ def print_all_run_times
37
+ StoreMeasurement.instance.print_all
38
+ end
39
+
40
+ def configuration
41
+ @configuration ||= Configuration.new
42
+ end
43
+
44
+ def included(base_class)
45
+ base_class.extend ClassMethods
46
+ # below creates two modules and then makes
47
+ # them accessible through a constant name
48
+ instance_interceptor = const_set(
49
+ instance_interceptor_name_for(base_class),
50
+ interceptor_module_for(base_class)
51
+ )
52
+ class_interceptor = const_set(
53
+ class_interceptor_name_for(base_class),
54
+ interceptor_module_for(base_class)
55
+ )
56
+
57
+ return unless should_run_and_time_methods?
58
+
59
+ base_class.prepend instance_interceptor
60
+ base_class.singleton_class.prepend class_interceptor
61
+ end
62
+
63
+ def instance_interceptor_name_for(base_class)
64
+ "#{base_class.time_method_name}InstanceInterceptor"
65
+ end
66
+
67
+ def class_interceptor_name_for(base_class)
68
+ "#{base_class.time_method_name}ClassInterceptor"
69
+ end
70
+
71
+
72
+ def interceptor_module_for(base_class)
73
+ Module.new do
74
+ @klass_name = base_class
75
+ def self.klass_name
76
+ @klass_name
77
+ end
78
+ end
79
+ end
80
+
81
+ def should_run_and_time_methods?
82
+ configuration.enable_time_method
83
+ end
84
+ end
85
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: time_method
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Seyon Vasantharajan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-02-13 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.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: 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
+ - !ruby/object:Gem::Dependency
56
+ name: terminal-table
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: " Time Method allows easy setting of runtime without
70
+ having to alter \n the code of the methods and also allows\n"
71
+ email:
72
+ - seyon.vasantharajan@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - README.md
82
+ - Rakefile
83
+ - img_1.png
84
+ - lib/time_method.rb
85
+ - lib/time_method/class_methods.rb
86
+ - lib/time_method/configuration.rb
87
+ - lib/time_method/measurement.rb
88
+ - lib/time_method/store_measurement.rb
89
+ - lib/time_method/version.rb
90
+ - license.txt
91
+ - time_method.gemspec
92
+ - time_method.rb
93
+ homepage: https://github.com/seyonv/time_method
94
+ licenses: []
95
+ metadata: {}
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ - lib/time_method
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.6.10
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Easily set methods to profile and view run-times in terminal
117
+ test_files: []