yuslow 0.0.2 → 0.0.3

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 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