yuslow 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfd953740e32fb7b75846380345a9574985088e04515198336ded5a33fe3953a
4
- data.tar.gz: 5c611848b2a5be441b54063854cf65e127bf323266f3e7f48ba44f1fc5a2d837
3
+ metadata.gz: 5246c2535d0277df7d0117c0abdb1a9ce9eeb49c434d0df1db0bfa85f71fbdd5
4
+ data.tar.gz: e2408ca24e820cd5d91cfa10b441bbbf8246e7476f7aab48f657bc6cd82fe1b8
5
5
  SHA512:
6
- metadata.gz: bad736143507ff82c224514901d4f375aeed60d5666772817cf8d764f45cec5f42d6a8d85231de60f29b7e3ce46bed39fdc5ed7860874f5dc4e2c80a65f6355f
7
- data.tar.gz: ed0bba601e95633f94e97ae6b17db4f9d93e0249dfbee20258cb1629e4d1ddc8f534cc435fac00dd624a6bdc7628deeb64214ed6f2b4972135c896e8c5b42696
6
+ metadata.gz: a89ddd6dd6063d40a3614904226728771d15f746a29d326e2b01cc96b2f6895f01e0366c375b6dccb6862a1492cebb94386e4e0a176bf88266d8f61c0c26b482
7
+ data.tar.gz: 9c0c568bcd841ac8b0e78927b00fa7cc73d1bdf4cb0bc2a6e140679de948d5e853210798137158c6403583f1fa07d6cf7a1a1172418284dbbc108e4126538ec9
@@ -0,0 +1,44 @@
1
+ # Yuslow
2
+ Yuslow `[waɪ ju sləʊ]` is a lightweight profiler for Ruby designed to debug slow parts of your system.
3
+
4
+ ## Install
5
+
6
+ ```
7
+ gem install yuslow
8
+ ```
9
+
10
+ ## Usage
11
+ Require the gem in the file which you would like to investigate.
12
+
13
+ ```ruby
14
+ require 'yuslow'
15
+ ```
16
+
17
+ then add
18
+
19
+ ```ruby
20
+ Yuslow.run do
21
+ a_very_slow_method
22
+ end
23
+ ```
24
+
25
+ or
26
+
27
+ ```ruby
28
+ investigation = Yuslow.investigation
29
+
30
+ investigation.start
31
+ a_very_slow_method
32
+ investigation.finish
33
+ ```
34
+
35
+ to your code. Execute the code and you will see output in $stdout with the following tree structure. It will help you understand which branch and method of your code has poor performance.
36
+
37
+ ```
38
+ Thread[1]:
39
+ Object#very_slow elapsed 1000 ms
40
+ Object#not_my_fault elapsed 1000 ms
41
+ Object#not_me elapsed 0 ms
42
+ Object#root_cause elapsed 1000 ms
43
+ Kernel#sleep elapsed 1000 ms
44
+ ```
@@ -0,0 +1,72 @@
1
+ module Yuslow
2
+ class Investigation
3
+ def initialize(debug: false, printer: nil)
4
+ @printer = printer
5
+ @debug = debug
6
+ @tracing = false
7
+ @trace = nil
8
+ @indent = 0
9
+ @execution = {}
10
+ end
11
+
12
+ def start
13
+ @trace = TracePoint.new(:call, :return, :c_call, :c_return) do |trace_point|
14
+ thread_id = Thread.current.object_id
15
+ @execution[thread_id] ||= {root: nil, current: nil}
16
+
17
+ if trace_point.defined_class == self.class && trace_point.callee_id == :start
18
+ @tracing = true
19
+ elsif trace_point.defined_class == self.class && trace_point.callee_id == :finish
20
+ @tracing = false
21
+ elsif @tracing
22
+ if %i(call c_call).include? trace_point.event
23
+ if @execution[thread_id][:current]
24
+ @execution[thread_id][:current] =
25
+ @execution[thread_id][:current].fork object: trace_point.defined_class,
26
+ method: trace_point.callee_id
27
+ else
28
+ operation = Operation.new object: trace_point.defined_class, method: trace_point.callee_id
29
+ @execution[thread_id][:root] = operation
30
+ @execution[thread_id][:current] = operation
31
+ end
32
+
33
+ debug trace_point, @indent
34
+ @indent += 1
35
+
36
+ elsif %i(return c_return).include? trace_point.event
37
+ @indent -= 1
38
+ debug trace_point, @indent
39
+
40
+ @execution[thread_id][:current]&.complete
41
+ @execution[thread_id][:current] = @execution[thread_id][:current]&.parent
42
+ end
43
+ end
44
+ end
45
+
46
+ @trace.enable
47
+ end
48
+
49
+ def finish
50
+ @trace.disable
51
+
52
+ print_result @printer if @printer
53
+ end
54
+
55
+ def debug(trace_point, indent)
56
+ return unless @debug
57
+
58
+ puts (' ' * indent) + "#{trace_point.event} #{trace_point.defined_class}##{trace_point.callee_id}"
59
+ end
60
+
61
+ def print_result(printer)
62
+ return unless printer
63
+
64
+ operations =
65
+ @execution.keys.map do |thread_id|
66
+ @execution[thread_id][:root]
67
+ end
68
+
69
+ printer.execute operations
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,39 @@
1
+ class Operation
2
+ attr_reader :parent, :children
3
+
4
+ class << self
5
+ def start(object, method)
6
+ new(object, method)
7
+ end
8
+ end
9
+
10
+ def initialize(object:, method:, parent: nil, started_at: Time.now, completed_at: nil, children: [])
11
+ @object = object
12
+ @method = method
13
+ @started_at = started_at
14
+ @completed_at = completed_at
15
+ @parent = parent
16
+ @children = children
17
+ end
18
+
19
+ def fork(object:, method:)
20
+ operation = self.class.new object: object, method: method, parent: self
21
+ @children << operation
22
+
23
+ operation
24
+ end
25
+
26
+ def identifier
27
+ "#{@object}##{@method}"
28
+ end
29
+
30
+ def complete
31
+ raise 'This operation is already completed' if @completed_at
32
+
33
+ @completed_at = Time.now
34
+ end
35
+
36
+ def elapsed
37
+ ((@completed_at - @started_at) * 1000).round if @completed_at
38
+ end
39
+ end
@@ -0,0 +1,60 @@
1
+ module Yuslow
2
+ module StdoutPrinter
3
+ extend self
4
+
5
+ def execute(operations, colorize = true)
6
+ output = []
7
+
8
+ operations.each_with_index.map do |operation, index|
9
+ output << "Thread[#{index + 1}]:"
10
+ output << stringify_operation(operation, 1, colorize)
11
+ output << nil
12
+ end
13
+
14
+ print output.join "\n"
15
+ end
16
+
17
+ def stringify_operation(operation, indent, colorize)
18
+ output = []
19
+ indentation = ' ' * indent
20
+
21
+ if operation.elapsed
22
+ identifier = operation.identifier
23
+ identifier = colorize(identifier, :green) if colorize
24
+
25
+ elapsed = operation.elapsed
26
+ elapsed = colorize(elapsed, :white) if colorize
27
+
28
+ output << "#{indentation}#{identifier} elapsed #{elapsed} ms"
29
+ else
30
+ text = "#{operation.identifier} did not finish"
31
+ colorize(text, :red) if colorize
32
+
33
+ output << "#{indentation}#{text}"
34
+ end
35
+
36
+ operation.children.each do |child_operation|
37
+ output << stringify_operation(child_operation, indent + 1, colorize)
38
+ end
39
+
40
+ output.join "\n"
41
+ end
42
+
43
+ def colorize(text, color)
44
+ code =
45
+ case color
46
+ when :black then '30'
47
+ when :red then '31'
48
+ when :green then '32'
49
+ when :white then '1;37'
50
+ when :bg_black then '40'
51
+ when :bg_red then '41'
52
+ when :bg_green then '42'
53
+ else
54
+ 0
55
+ end
56
+
57
+ "\e[#{code}m#{text}\e[0m"
58
+ end
59
+ end
60
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yuslow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Deyan Dobrinov
@@ -31,7 +31,11 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
+ - README.md
34
35
  - lib/yuslow.rb
36
+ - lib/yuslow/investigation.rb
37
+ - lib/yuslow/operation.rb
38
+ - lib/yuslow/stdout_printer.rb
35
39
  homepage: https://github.com/dobrinov/yuslow
36
40
  licenses:
37
41
  - MIT